Compare commits

...

75 Commits

Author SHA1 Message Date
960321e9bd Update Dockerfile 2024-12-04 18:50:35 +00:00
309a53600c Added missing ovm l1 fee contract 2024-12-04 17:27:38 +00:00
6d5f2681f4 Add readonlyProvider for RpcSigner 2024-12-04 15:50:21 +00:00
93a2049879 Add dockerfile for deterministic build 2024-12-04 03:45:19 +00:00
8b6887108f Use simplified websnark & snarkjs
* Use simplified websnark & snarkjs
* Added Base & Blast pools
* Added additional pools for optimism & arbitrum
* Added token transfer events
2024-12-04 03:30:35 +00:00
b35e53ebdb Exclude new instances from schema checking 2024-11-23 16:24:17 +00:00
2337892195 Added ERC20Tornado instances on BSC 2024-11-23 16:00:02 +00:00
68fcf07c2a Include events from cache to be audited and saved 2024-11-19 22:42:50 +00:00
69f89ae597 Force module resolution to make webpack build deterministic 2024-11-19 05:43:13 +00:00
72c6b92b07 Add BaseMultiTornadoService 2024-11-19 05:04:13 +00:00
b65998fca5 Add multiQueryFilter function 2024-11-18 02:52:03 +00:00
092989ebaa Temporary disable tornado nodes 2024-11-16 19:37:40 +00:00
94a62e6193 Added IPFS CID funcs 2024-11-10 23:55:42 +00:00
88b6e20aa1 Remove CORS check on relayers.json 2024-11-09 19:48:45 +00:00
df54da689c Fixed provider timeouts 2024-11-06 10:00:28 +00:00
efda9143dd Added additional RelayerRegistry events 2024-11-03 02:41:14 +00:00
f411159f15 Use 4 tab size and remove unused event constructor params 2024-11-01 00:30:14 +00:00
68f2e006ce Improve EncryptedNotes 2024-10-26 18:54:31 +00:00
b9fa95f5be Added IP fetch func 2024-10-25 14:09:24 +00:00
69066e4fd1 Use tornado.ws for deps 2024-10-25 13:22:25 +00:00
34d687c319 Improve parsing notes 2024-10-24 12:38:27 +00:00
55d62f7973 Added Permit Func 2024-10-24 00:25:44 +00:00
e3dc748020 Temporary use codeberg repo 2024-10-23 23:39:49 +00:00
9f4044d110 Make tree generation optional 2024-10-21 22:00:14 +00:00
6549fac5dd Added testnet oracle 2024-10-21 21:10:19 +00:00
3d3b987635 Added missing DB indexes 2024-10-21 15:23:26 +00:00
dfb20aa617 Added more DB services 2024-10-21 05:05:39 +00:00
ddf306a835 Added ENS functions ported from ensjs 2024-10-19 16:25:20 +00:00
75f57937e3 Improve Governance Functions 2024-10-18 14:17:00 +00:00
6ab73c7d59 Added numberFormatter 2024-10-18 13:23:14 +00:00
8600bd8842 Added Governance Event Functions 2024-10-18 02:18:06 +00:00
0e2da438ca Simplify class constructors 2024-10-16 15:19:31 +00:00
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
4f0aaea790 Add gasPrice function for FeeOracle 2024-10-10 18:34:38 +00:00
d87e6c51f7 Bump deps version 2024-10-10 05:40:40 +00:00
0ebd4d175f Expand timeout for relayers 2024-10-08 00:04:01 +00:00
fb33815290 Added missing contracts export 2024-10-07 12:32:42 +00:00
901281a59d Fixed browser provider 2024-10-06 23:04:59 +00:00
b9f891644d Build umd lib for @tornado/contracts 2024-10-06 22:23:56 +00:00
4517393017 Add missing variable for worker 2024-10-06 02:29:21 +00:00
51f737b728 Add digest params 2024-10-05 21:05:09 +00:00
58b3110125 Added logging for unzip 2024-10-04 17:11:28 +00:00
42db44ca3b IndexedDB 2024-10-04 12:58:47 +00:00
f73b9ecbff tornado-core 1.0.19
* fixed tovarish client bug
2024-10-02 19:23:55 +00:00
2092214da2 tornado-core 1.0.18
* improved events
2024-10-02 12:50:25 +00:00
4a884e4f41 tornado-core 1.0.17
* add static relayer
* removed rpc that censors transactions
2024-10-01 23:27:23 +00:00
6aa7ecd311 Bump deps version 2024-09-30 15:11:48 +00:00
0d159939d9 Validate fetched events from relayer 2024-09-30 14:34:30 +00:00
61266bdb6e Add latestBalance params 2024-09-30 06:22:40 +00:00
a00dab8d06 Initial client for Tovarish Relayer 2024-09-29 18:15:28 +00:00
be0e2419aa Add block num params for relayers event 2024-09-29 05:56:53 +00:00
bdcf48db73 Add getTovarishType for events 2024-09-29 03:49:00 +00:00
df1fcebfe3 tornado-core 1.0.16
* simplify populateTransaction func
* fixed relayerClient type defs
2024-09-28 02:42:27 +00:00
82aeabd739 Allow custom URL format relayers
should be convenient  to test locally
2024-09-27 04:56:19 +00:00
c155649719 Fixed snarkArgs type defs 2024-09-26 12:29:29 +00:00
69faa7a974 tornado-core 1.0.15
use more universal type defs for snark proofs
2024-09-26 12:23:55 +00:00
f7fdf7db0a tornado-core 1.0.14
* disable relayer version checks

* disable inactive cdai, usdc, usdt pools
2024-09-25 07:37:57 +00:00
d0b032d7be tornado-core 1.0.13
audit provider networks
2024-09-24 05:27:35 +00:00
20368b243b tornado-core 1.0.12
added minified umd files
2024-09-23 23:37:15 +00:00
29744cfce4 tornado-core 1.0.11
fixed encryptedNote filtering bug
2024-09-23 04:26:07 +00:00
48bb7aed82 Use @tornado/contracts 1.0.1 2024-09-22 15:07:01 +00:00
d6cfea1d19 tornado-core 1.0.10
revert reverse ordering for relayers
2024-09-22 05:56:21 +00:00
0bd87f9b67 tornado-core 1.0.9
optimize getting events
2024-09-22 03:16:12 +00:00
2bd991aa45 tornado-core 1.0.8
* minor fix
2024-09-22 02:37:33 +00:00
700426acb7 tornado-core 1.0.7
revert back to .ws
2024-09-21 17:25:44 +00:00
ef56beb29b tornado-core 1.0.6
* fixed save condition
2024-09-21 03:56:48 +00:00
e506c373de tornado-core 1.0.5
* support saving relayers
2024-09-21 02:55:32 +00:00
3df238e55f tornado-core 1.0.4
* remove obsolete rpc urls
2024-09-19 18:34:36 +00:00
95dbf208c3 tornado-core 1.0.3
* Removed polygon gas oracle and use default oracle provided by ethers.js

* Simplify events saving process

* Use codeberg.org to fetch dependencies

* Update dependencies
2024-09-19 17:49:25 +00:00
84b6ed368e Tornado Core 1.0.2 2024-06-29 17:02:29 -07:00
391ca0df37 Removed obsolete rpc endpoints 2024-06-29 16:54:30 -07:00
cf9e32f46d Disable fee bump for BSC by default 2024-05-15 08:55:32 +00:00
29bd7dc66e Improve op l1 fee calculation 2024-05-12 23:18:54 +00:00
b32cf2dbbc Tornado Core 1.0.1 2024-05-12 13:24:02 +00:00
117 changed files with 172571 additions and 50125 deletions

View File

@@ -1,65 +1,44 @@
module.exports = {
"env": {
"es2021": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:import/recommended",
"plugin:import/typescript",
"prettier",
"plugin:prettier/recommended",
],
"overrides": [
{
"env": {
"node": true
},
"files": [
".eslintrc.{js,cjs}"
],
"parserOptions": {
"sourceType": "script"
}
}
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"@typescript-eslint",
"prettier"
],
"rules": {
"prettier/prettier": [
"error",
{
singleQuote: true,
printWidth: 120
}
env: {
es2021: true,
node: true,
},
extends: [
'prettier',
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:import/recommended',
'plugin:import/typescript',
'plugin:prettier/recommended',
],
"import/order": ["error"],
/**
"indent": [
"error",
2
overrides: [
{
env: {
node: true,
},
files: ['.eslintrc.{js,cjs}'],
parserOptions: {
sourceType: 'script',
},
},
],
**/
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
],
"@typescript-eslint/no-unused-vars": ["warn"]
}
}
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
plugins: ['@typescript-eslint', 'prettier'],
rules: {
'prettier/prettier': [
'error',
{
tabWidth: 4,
printWidth: 120,
singleQuote: true,
},
],
'import/order': ['error'],
'@typescript-eslint/no-unused-vars': ['warn'],
'@typescript-eslint/no-unused-expressions': ['off'],
},
};

10
.gitignore vendored
View File

@@ -1,7 +1,7 @@
node_modules
.env
/events
/trees
backup-tornado-*
backup-tornadoInvoice-*
backup-note-account-*
# coverage files
/coverage
/coverage.json
.nyc_output

13
.nycrc Normal file
View File

@@ -0,0 +1,13 @@
{
"all": true,
"extension": [".ts"],
"report-dir": "coverage",
"reporter": [
"html",
"lcov",
"text",
"text-summary"
],
"include": ["src/**/*.ts"],
"exclude": ["src/typechain/**/*"]
}

25
Dockerfile Normal file
View File

@@ -0,0 +1,25 @@
# Dockefile from https://notes.ethereum.org/@GW1ZUbNKR5iRjjKYx6_dJQ/Bk8zsJ9xj
# FROM node:20.18.0-bullseye-slim
FROM node@sha256:9b558df8f10198fcd1f48cf344c55c4442c3446b8a9a69487523b3d890a4a59e
# install wget, git and necessary certificates
RUN apt update && apt install --yes --no-install-recommends wget git apt-transport-https ca-certificates && rm -rf /var/lib/apt/lists/*
ENV GIT_REPOSITORY=https://git.tornado.ws/tornadocontrib/tornado-core.git
# From development branch, double check with tornado.ws
ENV GIT_COMMIT_HASH=309a53600ce4e17b8d3225ca5923bdf280edaaf0
# clone the repository
RUN mkdir /app/
WORKDIR /app
# Simple hack to fetch only commit and nothing more (no need to download 1GB sized repo, only 100MB would be enough)
RUN git init && \
git remote add origin $GIT_REPOSITORY && \
git fetch --depth 1 origin $GIT_COMMIT_HASH && \
git checkout $GIT_COMMIT_HASH
# install, build and prep for deployment
RUN yarn install --frozen-lockfile --ignore-scripts
RUN yarn build

24
dist/batch.d.ts vendored
View File

@@ -1,4 +1,14 @@
import type { Provider, BlockTag, Block, TransactionResponse, BaseContract, ContractEventName, EventLog } from 'ethers';
import { Provider, BlockTag, Block, TransactionResponse, BaseContract, ContractEventName, EventLog, TransactionReceipt, EventFragment, TopicFilter, Interface, Log } from 'ethers';
/**
* Copied from ethers.js as they don't export this function
* https://github.com/ethers-io/ethers.js/blob/main/src.ts/contract/contract.ts#L464
*/
export declare function getSubInfo(abiInterface: Interface, event: ContractEventName): Promise<{
fragment: null | EventFragment;
tag: string;
topics: TopicFilter;
}>;
export declare function multiQueryFilter(address: string | string[], contract: BaseContract, event: ContractEventName, fromBlock?: BlockTag, toBlock?: BlockTag): Promise<Log[]>;
export interface BatchBlockServiceConstructor {
provider: Provider;
onProgress?: BatchBlockOnProgress;
@@ -42,12 +52,15 @@ export declare class BatchTransactionService {
retryOn: number;
constructor({ provider, onProgress, concurrencySize, batchSize, shouldRetry, retryMax, retryOn, }: BatchBlockServiceConstructor);
getTransaction(txHash: string): Promise<TransactionResponse>;
createBatchRequest(batchArray: string[][]): Promise<TransactionResponse[]>[];
getTransactionReceipt(txHash: string): Promise<TransactionReceipt>;
createBatchRequest(batchArray: string[][], receipt?: boolean): Promise<TransactionResponse[] | TransactionReceipt[]>[];
getBatchTransactions(txs: string[]): Promise<TransactionResponse[]>;
getBatchReceipt(txs: string[]): Promise<TransactionReceipt[]>;
}
export interface BatchEventServiceConstructor {
provider: Provider;
contract: BaseContract;
address?: string | string[];
onProgress?: BatchEventOnProgress;
concurrencySize?: number;
blocksPerRequest?: number;
@@ -62,24 +75,25 @@ export type BatchEventOnProgress = ({ percentage, type, fromBlock, toBlock, coun
toBlock?: number;
count?: number;
}) => void;
export type EventInput = {
export interface EventInput {
fromBlock: number;
toBlock: number;
type: ContractEventName;
};
}
/**
* Fetch events from web3 provider on bulk
*/
export declare class BatchEventsService {
provider: Provider;
contract: BaseContract;
address?: string | string[];
onProgress?: BatchEventOnProgress;
concurrencySize: number;
blocksPerRequest: number;
shouldRetry: boolean;
retryMax: number;
retryOn: number;
constructor({ provider, contract, onProgress, concurrencySize, blocksPerRequest, shouldRetry, retryMax, retryOn, }: BatchEventServiceConstructor);
constructor({ provider, contract, address, onProgress, concurrencySize, blocksPerRequest, shouldRetry, retryMax, retryOn, }: BatchEventServiceConstructor);
getPastEvents({ fromBlock, toBlock, type }: EventInput): Promise<EventLog[]>;
createBatchRequest(batchArray: EventInput[]): Promise<EventLog[]>[];
getBatchEvents({ fromBlock, toBlock, type }: EventInput): Promise<EventLog[]>;

2
dist/contracts.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
export * from '@tornado/contracts';
export { Multicall, Multicall__factory, OffchainOracle, OffchainOracle__factory, OvmGasPriceOracle, OvmGasPriceOracle__factory, ReverseRecords, ReverseRecords__factory, ENSNameWrapper, ENSNameWrapper__factory, ENSRegistry, ENSRegistry__factory, ENSResolver, ENSResolver__factory, } from './typechain';

40
dist/deposits.d.ts vendored
View File

@@ -1,36 +1,35 @@
import type { NetIdType } from './networkConfig';
export type DepositType = {
export interface DepositType {
currency: string;
amount: string;
netId: NetIdType;
};
export type createDepositParams = {
}
export interface createDepositParams {
nullifier: bigint;
secret: bigint;
};
export type createDepositObject = {
}
export interface createDepositObject {
preimage: Uint8Array;
noteHex: string;
commitment: bigint;
commitmentHex: string;
nullifierHash: bigint;
nullifierHex: string;
};
export type createNoteParams = DepositType & {
}
export interface createNoteParams extends DepositType {
nullifier?: bigint;
secret?: bigint;
};
export type parsedNoteExec = DepositType & {
}
export interface parsedNoteExec extends DepositType {
note: string;
};
export type depositTx = {
from: string;
transactionHash: string;
};
export type withdrawalTx = {
to: string;
transactionHash: string;
};
noteHex: string;
}
export interface parsedInvoiceExec extends DepositType {
invoice: string;
commitmentHex: string;
}
export declare function parseNote(noteString: string): parsedNoteExec | undefined;
export declare function parseInvoice(invoiceString: string): parsedInvoiceExec | undefined;
export declare function createDeposit({ nullifier, secret }: createDepositParams): Promise<createDepositObject>;
export interface DepositConstructor {
currency: string;
@@ -60,14 +59,11 @@ export declare class Deposit {
static createNote({ currency, amount, netId, nullifier, secret }: createNoteParams): Promise<Deposit>;
static parseNote(noteString: string): Promise<Deposit>;
}
export type parsedInvoiceExec = DepositType & {
commitment: string;
};
export declare class Invoice {
currency: string;
amount: string;
netId: NetIdType;
commitment: string;
commitmentHex: string;
invoice: string;
constructor(invoiceString: string);
toString(): string;

View File

@@ -1,8 +1,6 @@
import { EthEncryptedData } from '@metamask/eth-sig-util';
import { Echoer } from '@tornado/contracts';
import { Wallet } from 'ethers';
import { Signer, Wallet } from 'ethers';
import { EchoEvents, EncryptedNotesEvents } from './events';
import type { NetIdType } from './networkConfig';
export interface NoteToEncrypt {
address: string;
noteHex: string;
@@ -17,24 +15,20 @@ export declare function unpackEncryptedMessage(encryptedMessage: string): EthEnc
messageBuff: string;
};
export interface NoteAccountConstructor {
netId: NetIdType;
blockNumber?: number;
recoveryKey?: string;
Echoer: Echoer;
}
export declare class NoteAccount {
netId: NetIdType;
blockNumber?: number;
recoveryKey: string;
recoveryAddress: string;
recoveryPublicKey: string;
Echoer: Echoer;
constructor({ netId, blockNumber, recoveryKey, Echoer }: NoteAccountConstructor);
constructor({ blockNumber, recoveryKey }: NoteAccountConstructor);
/**
* Intends to mock eth_getEncryptionPublicKey behavior from MetaMask
* In order to make the recoveryKey retrival from Echoer possible from the bare private key
*/
static getWalletPublicKey(wallet: Wallet): string;
static getSignerPublicKey(signer: Signer | Wallet): Promise<string>;
getEncryptedAccount(walletPublicKey: string): {
encryptedData: EthEncryptedData;
data: string;
@@ -42,7 +36,7 @@ export declare class NoteAccount {
/**
* Decrypt Echoer backuped note encryption account with private keys
*/
decryptAccountsWithWallet(wallet: Wallet, events: EchoEvents[]): NoteAccount[];
static decryptSignerNoteAccounts(signer: Signer | Wallet, events: EchoEvents[]): Promise<NoteAccount[]>;
decryptNotes(events: EncryptedNotesEvents[]): DecryptedNotes[];
encryptNote({ address, noteHex }: NoteToEncrypt): string;
}

34
dist/ens.d.ts vendored Normal file
View File

@@ -0,0 +1,34 @@
import { EnsResolver, AbstractProvider, Signer } from 'ethers';
import { ENSNameWrapper, ENSRegistry, ENSResolver } from './typechain';
import { NetIdType } from './networkConfig';
export declare function encodedLabelToLabelhash(label: string): string | null;
export declare function labelhash(label: string): string;
export declare function makeLabelNodeAndParent(name: string): {
label: string;
labelhash: string;
parentNode: string;
};
export declare const EnsContracts: {
[key: NetIdType]: {
ensRegistry: string;
ensPublicResolver: string;
ensNameWrapper: string;
};
};
/**
* ENSUtils to manage on-chain registered relayers
*/
export declare class ENSUtils {
ENSRegistry?: ENSRegistry;
ENSResolver?: ENSResolver;
ENSNameWrapper?: ENSNameWrapper;
provider: AbstractProvider;
constructor(provider: AbstractProvider);
getContracts(): Promise<void>;
getOwner(name: string): Promise<string>;
unwrap(signer: Signer, name: string): Promise<import("ethers").ContractTransactionResponse>;
setSubnodeRecord(signer: Signer, name: string): Promise<import("ethers").ContractTransactionResponse>;
getResolver(name: string): Promise<EnsResolver | null>;
getText(name: string, key: string): Promise<string | null>;
setText(signer: Signer, name: string, key: string, value: string): Promise<import("ethers").ContractTransactionResponse>;
}

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

@@ -1,67 +1,53 @@
import { BaseContract, Provider, EventLog, ContractEventName } from 'ethers';
import type { Tornado, TornadoRouter, TornadoProxyLight, Governance, RelayerRegistry, Echoer } from '@tornado/contracts';
import { BaseContract, Provider, EventLog } from 'ethers';
import { Tornado, TornadoRouter, TornadoProxyLight, Governance, RelayerRegistry, Echoer, Aggregator } from '@tornado/contracts';
import type { MerkleTree } from 'fixed-merkle-tree';
import { BatchEventsService, BatchBlockService, BatchTransactionService, BatchEventOnProgress, BatchBlockOnProgress } from '../batch';
import { fetchDataOptions } from '../providers';
import type { NetIdType } from '../networkConfig';
import type { BaseEvents, MinimalEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, AllGovernanceEvents, RegistersEvents, EchoEvents } from './types';
export declare const DEPOSIT = "deposit";
export declare const WITHDRAWAL = "withdrawal";
export type BaseEventsServiceConstructor = {
import { type NetIdType, type SubdomainMap } from '../networkConfig';
import { RelayerParams } from '../relayerClient';
import type { TovarishClient } from '../tovarishClient';
import type { ERC20, ReverseRecords } from '../typechain';
import type { MerkleTreeService } from '../merkleTree';
import type { DepositType } from '../deposits';
import type { BaseEvents, CachedEvents, MinimalEvents, DepositsEvents, WithdrawalsEvents, EncryptedNotesEvents, AllGovernanceEvents, GovernanceProposalCreatedEvents, GovernanceVotedEvents, EchoEvents, AllRelayerRegistryEvents, StakeBurnedEvents, MultiDepositsEvents, MultiWithdrawalsEvents, TransferEvents } from './types';
export interface BaseEventsServiceConstructor {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
contract: BaseContract;
type?: string;
type: string;
deployedBlock?: number;
fetchDataOptions?: fetchDataOptions;
};
export type BatchGraphOnProgress = ({ type, fromBlock, toBlock, count, }: {
type?: ContractEventName;
fromBlock?: number;
toBlock?: number;
count?: number;
}) => void;
export type BaseGraphParams = {
graphApi: string;
subgraphName: string;
fetchDataOptions?: fetchDataOptions;
onProgress?: BatchGraphOnProgress;
};
tovarishClient?: TovarishClient;
}
export declare class BaseEventsService<EventType extends MinimalEvents> {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
contract: BaseContract;
type: string;
deployedBlock: number;
batchEventsService: BatchEventsService;
fetchDataOptions?: fetchDataOptions;
saveEventsPromise?: Promise<void>;
constructor({ netId, provider, graphApi, subgraphName, contract, type, deployedBlock, fetchDataOptions, }: BaseEventsServiceConstructor);
tovarishClient?: TovarishClient;
constructor({ netId, provider, contract, type, deployedBlock, fetchDataOptions, tovarishClient, }: BaseEventsServiceConstructor);
getInstanceName(): string;
getType(): string;
getGraphMethod(): string;
getGraphParams(): BaseGraphParams;
getTovarishType(): string;
updateEventProgress({ percentage, type, fromBlock, toBlock, count }: Parameters<BatchEventOnProgress>[0]): void;
updateBlockProgress({ percentage, currentIndex, totalIndex }: Parameters<BatchBlockOnProgress>[0]): void;
updateTransactionProgress({ percentage, currentIndex, totalIndex }: Parameters<BatchBlockOnProgress>[0]): void;
updateGraphProgress({ type, fromBlock, toBlock, count }: Parameters<BatchGraphOnProgress>[0]): void;
formatEvents(events: EventLog[]): Promise<EventType[]>;
/**
* Get saved or cached events
*/
getEventsFromDB(): Promise<BaseEvents<EventType>>;
getEventsFromCache(): Promise<BaseEvents<EventType>>;
getSavedEvents(): Promise<BaseEvents<EventType>>;
/**
* Get latest events
* Events from remote cache (Either from local cache, CDN, or from IPFS)
*/
getEventsFromGraph({ fromBlock, methodName, }: {
fromBlock: number;
methodName?: string;
}): Promise<BaseEvents<EventType>>;
getEventsFromCache(): Promise<CachedEvents<EventType>>;
/**
* This may not return in sorted events when called from browser, make sure to sort it again when directly called
*/
getSavedEvents(): Promise<BaseEvents<EventType> | CachedEvents<EventType>>;
getEventsFromRpc({ fromBlock, toBlock, }: {
fromBlock: number;
toBlock?: number;
@@ -69,124 +55,210 @@ export declare class BaseEventsService<EventType extends MinimalEvents> {
getLatestEvents({ fromBlock }: {
fromBlock: number;
}): Promise<BaseEvents<EventType>>;
validateEvents({ events, lastBlock }: BaseEvents<EventType>): void;
validateEvents<S>({ events, newEvents, lastBlock, }: BaseEvents<EventType> & {
newEvents: EventType[];
}): Promise<S>;
/**
* Handle saving events
*/
saveEvents({ events, lastBlock }: BaseEvents<EventType>): Promise<void>;
saveEvents({ events, newEvents, lastBlock }: BaseEvents<EventType> & {
newEvents: EventType[];
}): Promise<void>;
/**
* Trigger saving and receiving latest events
*/
updateEvents(): Promise<{
updateEvents<S>(): Promise<{
events: EventType[];
lastBlock: number | null;
lastBlock: number;
validateResult: Awaited<S>;
}>;
}
export type BaseTornadoServiceConstructor = {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
export interface BaseTornadoServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract'> {
Tornado: Tornado;
type: string;
amount: string;
currency: string;
deployedBlock?: number;
fetchDataOptions?: fetchDataOptions;
};
export type DepositsGraphParams = BaseGraphParams & {
amount: string;
currency: string;
};
optionalTree?: boolean;
merkleTreeService?: MerkleTreeService;
}
export declare class BaseTornadoService extends BaseEventsService<DepositsEvents | WithdrawalsEvents> {
amount: string;
currency: string;
optionalTree?: boolean;
merkleTreeService?: MerkleTreeService;
batchTransactionService: BatchTransactionService;
batchBlockService: BatchBlockService;
constructor({ netId, provider, graphApi, subgraphName, Tornado, type, amount, currency, deployedBlock, fetchDataOptions, }: BaseTornadoServiceConstructor);
constructor(serviceConstructor: BaseTornadoServiceConstructor);
getInstanceName(): string;
getGraphMethod(): string;
getGraphParams(): DepositsGraphParams;
formatEvents(events: EventLog[]): Promise<(DepositsEvents | WithdrawalsEvents)[]>;
validateEvents({ events }: {
events: (DepositsEvents | WithdrawalsEvents)[];
}): void;
}
export type BaseEchoServiceConstructor = {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
Echoer: Echoer;
deployedBlock?: number;
fetchDataOptions?: fetchDataOptions;
};
export declare class BaseEchoService extends BaseEventsService<EchoEvents> {
constructor({ netId, provider, graphApi, subgraphName, Echoer, deployedBlock, fetchDataOptions, }: BaseEchoServiceConstructor);
getInstanceName(): string;
getType(): string;
getGraphMethod(): string;
formatEvents(events: EventLog[]): Promise<EchoEvents[]>;
getEventsFromGraph({ fromBlock }: {
validateEvents<S>({ events, newEvents, }: BaseEvents<DepositsEvents | WithdrawalsEvents> & {
newEvents: (DepositsEvents | WithdrawalsEvents)[];
}): Promise<S>;
getLatestEvents({ fromBlock, }: {
fromBlock: number;
}): Promise<BaseEvents<EchoEvents>>;
}): Promise<BaseEvents<DepositsEvents | WithdrawalsEvents>>;
}
export type BaseEncryptedNotesServiceConstructor = {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
Router: TornadoRouter | TornadoProxyLight;
deployedBlock?: number;
fetchDataOptions?: fetchDataOptions;
};
export declare class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesEvents> {
constructor({ netId, provider, graphApi, subgraphName, Router, deployedBlock, fetchDataOptions, }: BaseEncryptedNotesServiceConstructor);
export interface BaseMultiTornadoServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
instances: {
[key in string]: DepositType;
};
optionalTree?: boolean;
merkleTreeService?: MerkleTreeService;
}
export declare class BaseMultiTornadoService extends BaseEventsService<MultiDepositsEvents | MultiWithdrawalsEvents> {
instances: {
[key in string]: DepositType;
};
optionalTree?: boolean;
merkleTreeService?: MerkleTreeService;
batchTransactionService: BatchTransactionService;
batchBlockService: BatchBlockService;
constructor(serviceConstructor: BaseMultiTornadoServiceConstructor);
getInstanceName(): string;
getType(): string;
getGraphMethod(): string;
getTovarishType(): string;
formatEvents(events: EventLog[]): Promise<(MultiDepositsEvents | MultiWithdrawalsEvents)[]>;
validateEvents<S>({ events, newEvents, }: BaseEvents<MultiDepositsEvents | MultiWithdrawalsEvents> & {
newEvents: (MultiDepositsEvents | MultiWithdrawalsEvents)[];
}): Promise<S>;
getEvents(instanceAddress: string): Promise<{
depositEvents: MultiDepositsEvents[];
withdrawalEvents: MultiWithdrawalsEvents[];
tree: MerkleTree | undefined;
lastBlock: number;
}>;
}
export interface BaseEchoServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
Echoer: Echoer;
}
export declare class BaseEchoService extends BaseEventsService<EchoEvents> {
constructor(serviceConstructor: BaseEchoServiceConstructor);
getInstanceName(): string;
formatEvents(events: EventLog[]): Promise<EchoEvents[]>;
}
export interface BaseEncryptedNotesServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
Router: TornadoRouter | TornadoProxyLight;
}
export declare class BaseEncryptedNotesService extends BaseEventsService<EncryptedNotesEvents> {
constructor(serviceConstructor: BaseEncryptedNotesServiceConstructor);
getInstanceName(): string;
getTovarishType(): string;
formatEvents(events: EventLog[]): Promise<EncryptedNotesEvents[]>;
}
export type BaseGovernanceServiceConstructor = {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
export declare const proposalState: {
[key: string]: string;
};
export interface GovernanceProposals extends GovernanceProposalCreatedEvents {
title: string;
proposerName?: string;
forVotes: bigint;
againstVotes: bigint;
executed: boolean;
extended: boolean;
quorum: string;
state: string;
}
export interface GovernanceVotes extends GovernanceVotedEvents {
contact: string;
message: string;
fromName?: string;
voterName?: string;
}
export interface BaseGovernanceServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
Governance: Governance;
deployedBlock?: number;
fetchDataOptions?: fetchDataOptions;
};
Aggregator: Aggregator;
ReverseRecords: ReverseRecords;
}
export declare class BaseGovernanceService extends BaseEventsService<AllGovernanceEvents> {
Governance: Governance;
Aggregator: Aggregator;
ReverseRecords: ReverseRecords;
batchTransactionService: BatchTransactionService;
constructor({ netId, provider, graphApi, subgraphName, Governance, deployedBlock, fetchDataOptions, }: BaseGovernanceServiceConstructor);
constructor(serviceConstructor: BaseGovernanceServiceConstructor);
getInstanceName(): string;
getType(): string;
getGraphMethod(): string;
getTovarishType(): string;
formatEvents(events: EventLog[]): Promise<AllGovernanceEvents[]>;
getEventsFromGraph({ fromBlock }: {
fromBlock: number;
}): Promise<BaseEvents<AllGovernanceEvents>>;
getAllProposals(): Promise<GovernanceProposals[]>;
getVotes(proposalId: number): Promise<GovernanceVotes[]>;
getDelegatedBalance(ethAccount: string): Promise<{
delegatedAccs: string[];
undelegatedAccs: string[];
uniq: string[];
uniqNames: {
[key: string]: string;
};
balances: bigint[];
balance: bigint;
}>;
}
export type BaseRegistryServiceConstructor = {
netId: NetIdType;
provider: Provider;
graphApi?: string;
subgraphName?: string;
export declare function getTovarishNetworks(registryService: BaseRegistryService, relayers: CachedRelayerInfo[]): Promise<void>;
/**
* Essential params:
* ensName, relayerAddress, hostnames
* Other data is for historic purpose from relayer registry
*/
export interface CachedRelayerInfo extends RelayerParams {
isRegistered?: boolean;
registeredAddress?: string;
stakeBalance?: string;
hostnames: SubdomainMap;
tovarishHost?: string;
tovarishNetworks?: number[];
}
export interface CachedRelayers {
lastBlock: number;
timestamp: number;
relayers: CachedRelayerInfo[];
fromCache?: boolean;
}
export interface BaseRegistryServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
RelayerRegistry: RelayerRegistry;
deployedBlock?: number;
fetchDataOptions?: fetchDataOptions;
};
export declare class BaseRegistryService extends BaseEventsService<RegistersEvents> {
constructor({ netId, provider, graphApi, subgraphName, RelayerRegistry, deployedBlock, fetchDataOptions, }: BaseRegistryServiceConstructor);
getInstanceName(): string;
getType(): string;
getGraphMethod(): string;
formatEvents(events: EventLog[]): Promise<{
ensName: any;
relayerAddress: any;
blockNumber: number;
logIndex: number;
transactionHash: string;
}[]>;
fetchRelayers(): Promise<RegistersEvents[]>;
Aggregator: Aggregator;
relayerEnsSubdomains: SubdomainMap;
}
export declare class BaseRegistryService extends BaseEventsService<AllRelayerRegistryEvents> {
Aggregator: Aggregator;
relayerEnsSubdomains: SubdomainMap;
updateInterval: number;
constructor(serviceConstructor: BaseRegistryServiceConstructor);
getInstanceName(): string;
getTovarishType(): string;
formatEvents(events: EventLog[]): Promise<AllRelayerRegistryEvents[]>;
/**
* Get saved or cached relayers
*/
getRelayersFromDB(): Promise<CachedRelayers>;
/**
* Relayers from remote cache (Either from local cache, CDN, or from IPFS)
*/
getRelayersFromCache(): Promise<CachedRelayers>;
getSavedRelayers(): Promise<CachedRelayers>;
getLatestRelayers(): Promise<CachedRelayers>;
/**
* Handle saving relayers
*/
saveRelayers({ lastBlock, timestamp, relayers }: CachedRelayers): Promise<void>;
/**
* Get cached or latest relayer and save to local
*/
updateRelayers(): Promise<CachedRelayers>;
}
export interface BaseRevenueServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
RelayerRegistry: RelayerRegistry;
}
/**
* Tracks TORN burned events from RelayerRegistry contract
*/
export declare class BaseRevenueService extends BaseEventsService<StakeBurnedEvents> {
batchTransactionService: BatchTransactionService;
batchBlockService: BatchBlockService;
constructor(serviceConstructor: BaseRevenueServiceConstructor);
getInstanceName(): string;
getTovarishType(): string;
formatEvents(events: EventLog[]): Promise<StakeBurnedEvents[]>;
}
export interface BaseTransferServiceConstructor extends Omit<BaseEventsServiceConstructor, 'contract' | 'type'> {
Token: ERC20;
}
export declare class BaseTransferService extends BaseEventsService<TransferEvents> {
constructor(serviceConstructor: BaseTransferServiceConstructor);
formatEvents(events: EventLog[]): Promise<TransferEvents[]>;
}

129
dist/events/db.d.ts vendored Normal file
View File

@@ -0,0 +1,129 @@
import { IndexedDB } from '../idb';
import { BaseTornadoService, BaseTornadoServiceConstructor, BaseEchoService, BaseEchoServiceConstructor, BaseEncryptedNotesService, BaseEncryptedNotesServiceConstructor, BaseGovernanceService, BaseGovernanceServiceConstructor, BaseRegistryService, BaseRegistryServiceConstructor, BaseRevenueService, BaseRevenueServiceConstructor, CachedRelayers, BaseMultiTornadoService, BaseMultiTornadoServiceConstructor } from './base';
import { BaseEvents, MinimalEvents, DepositsEvents, WithdrawalsEvents, CachedEvents, EchoEvents, EncryptedNotesEvents, AllGovernanceEvents, AllRelayerRegistryEvents, StakeBurnedEvents, MultiDepositsEvents, MultiWithdrawalsEvents } from './types';
export declare function saveDBEvents<T extends MinimalEvents>({ idb, instanceName, newEvents, lastBlock, }: {
idb: IndexedDB;
instanceName: string;
newEvents: T[];
lastBlock: number;
}): Promise<void>;
export declare function loadDBEvents<T extends MinimalEvents>({ idb, instanceName, }: {
idb: IndexedDB;
instanceName: string;
}): Promise<BaseEvents<T>>;
export declare function loadRemoteEvents<T extends MinimalEvents>({ staticUrl, instanceName, deployedBlock, zipDigest, }: {
staticUrl: string;
instanceName: string;
deployedBlock: number;
zipDigest?: string;
}): Promise<CachedEvents<T>>;
export interface DBTornadoServiceConstructor extends BaseTornadoServiceConstructor {
staticUrl: string;
idb: IndexedDB;
}
export declare class DBTornadoService extends BaseTornadoService {
staticUrl: string;
idb: IndexedDB;
zipDigest?: string;
constructor(params: DBTornadoServiceConstructor);
getEventsFromDB(): Promise<BaseEvents<DepositsEvents | WithdrawalsEvents>>;
getEventsFromCache(): Promise<CachedEvents<DepositsEvents | WithdrawalsEvents>>;
saveEvents({ newEvents, lastBlock, }: BaseEvents<DepositsEvents | WithdrawalsEvents> & {
newEvents: (DepositsEvents | WithdrawalsEvents)[];
}): Promise<void>;
}
export interface DBMultiTornadoServiceConstructor extends BaseMultiTornadoServiceConstructor {
staticUrl: string;
idb: IndexedDB;
}
export declare class DBMultiTornadoService extends BaseMultiTornadoService {
staticUrl: string;
idb: IndexedDB;
zipDigest?: string;
constructor(params: DBMultiTornadoServiceConstructor);
getEventsFromDB(): Promise<BaseEvents<MultiDepositsEvents | MultiWithdrawalsEvents>>;
getEventsFromCache(): Promise<CachedEvents<MultiDepositsEvents | MultiWithdrawalsEvents>>;
saveEvents({ newEvents, lastBlock, }: BaseEvents<MultiDepositsEvents | MultiWithdrawalsEvents> & {
newEvents: (MultiDepositsEvents | MultiWithdrawalsEvents)[];
}): Promise<void>;
}
export interface DBEchoServiceConstructor extends BaseEchoServiceConstructor {
staticUrl: string;
idb: IndexedDB;
}
export declare class DBEchoService extends BaseEchoService {
staticUrl: string;
idb: IndexedDB;
zipDigest?: string;
constructor(params: DBEchoServiceConstructor);
getEventsFromDB(): Promise<BaseEvents<EchoEvents>>;
getEventsFromCache(): Promise<CachedEvents<EchoEvents>>;
saveEvents({ newEvents, lastBlock }: BaseEvents<EchoEvents> & {
newEvents: EchoEvents[];
}): Promise<void>;
}
export interface DBEncryptedNotesServiceConstructor extends BaseEncryptedNotesServiceConstructor {
staticUrl: string;
idb: IndexedDB;
}
export declare class DBEncryptedNotesService extends BaseEncryptedNotesService {
staticUrl: string;
idb: IndexedDB;
zipDigest?: string;
constructor(params: DBEncryptedNotesServiceConstructor);
getEventsFromDB(): Promise<BaseEvents<EncryptedNotesEvents>>;
getEventsFromCache(): Promise<CachedEvents<EncryptedNotesEvents>>;
saveEvents({ newEvents, lastBlock, }: BaseEvents<EncryptedNotesEvents> & {
newEvents: EncryptedNotesEvents[];
}): Promise<void>;
}
export interface DBGovernanceServiceConstructor extends BaseGovernanceServiceConstructor {
staticUrl: string;
idb: IndexedDB;
}
export declare class DBGovernanceService extends BaseGovernanceService {
staticUrl: string;
idb: IndexedDB;
zipDigest?: string;
constructor(params: DBGovernanceServiceConstructor);
getEventsFromDB(): Promise<BaseEvents<AllGovernanceEvents>>;
getEventsFromCache(): Promise<CachedEvents<AllGovernanceEvents>>;
saveEvents({ newEvents, lastBlock }: BaseEvents<AllGovernanceEvents> & {
newEvents: AllGovernanceEvents[];
}): Promise<void>;
}
export interface DBRegistryServiceConstructor extends BaseRegistryServiceConstructor {
staticUrl: string;
idb: IndexedDB;
}
export declare class DBRegistryService extends BaseRegistryService {
staticUrl: string;
idb: IndexedDB;
zipDigest?: string;
relayerJsonDigest?: string;
constructor(params: DBRegistryServiceConstructor);
getEventsFromDB(): Promise<BaseEvents<AllRelayerRegistryEvents>>;
getEventsFromCache(): Promise<CachedEvents<AllRelayerRegistryEvents>>;
saveEvents({ newEvents, lastBlock, }: BaseEvents<AllRelayerRegistryEvents> & {
newEvents: AllRelayerRegistryEvents[];
}): Promise<void>;
getRelayersFromDB(): Promise<CachedRelayers>;
getRelayersFromCache(): Promise<CachedRelayers>;
saveRelayers(cachedRelayers: CachedRelayers): Promise<void>;
}
export interface DBRevenueServiceConstructor extends BaseRevenueServiceConstructor {
staticUrl: string;
idb: IndexedDB;
}
export declare class DBRevenueService extends BaseRevenueService {
staticUrl: string;
idb: IndexedDB;
zipDigest?: string;
relayerJsonDigest?: string;
constructor(params: DBRevenueServiceConstructor);
getEventsFromDB(): Promise<BaseEvents<StakeBurnedEvents>>;
getEventsFromCache(): Promise<CachedEvents<StakeBurnedEvents>>;
saveEvents({ newEvents, lastBlock }: BaseEvents<StakeBurnedEvents> & {
newEvents: StakeBurnedEvents[];
}): Promise<void>;
}

View File

@@ -1,2 +1,3 @@
export * from './types';
export * from './base';
export * from './db';

View File

@@ -1,7 +1,10 @@
import { RelayerParams } from '../relayerClient';
export interface BaseEvents<T> {
events: T[];
lastBlock: number | null;
lastBlock: number;
}
export interface CachedEvents<T> extends BaseEvents<T> {
fromCache: boolean;
}
export interface BaseGraphEvents<T> {
events: T[];
@@ -12,51 +15,92 @@ export interface MinimalEvents {
logIndex: number;
transactionHash: string;
}
export type GovernanceEvents = MinimalEvents & {
export interface GovernanceEvents extends MinimalEvents {
event: string;
};
export type GovernanceProposalCreatedEvents = GovernanceEvents & {
}
export interface GovernanceProposalCreatedEvents extends GovernanceEvents {
id: number;
proposer: string;
target: string;
startTime: number;
endTime: number;
description: string;
};
export type GovernanceVotedEvents = GovernanceEvents & {
}
export interface GovernanceVotedEvents extends GovernanceEvents {
proposalId: number;
voter: string;
support: boolean;
votes: string;
from: string;
input: string;
};
export type GovernanceDelegatedEvents = GovernanceEvents & {
}
export interface GovernanceDelegatedEvents extends GovernanceEvents {
account: string;
delegateTo: string;
};
export type GovernanceUndelegatedEvents = GovernanceEvents & {
}
export interface GovernanceUndelegatedEvents extends GovernanceEvents {
account: string;
delegateFrom: string;
};
}
export type AllGovernanceEvents = GovernanceProposalCreatedEvents | GovernanceVotedEvents | GovernanceDelegatedEvents | GovernanceUndelegatedEvents;
export interface RelayerRegistryEvents extends MinimalEvents {
event: string;
}
export interface RelayerRegisteredEvents extends RelayerRegistryEvents, RelayerParams {
ensHash: string;
stakedAmount: string;
}
export interface RelayerUnregisteredEvents extends RelayerRegistryEvents {
relayerAddress: string;
}
export interface WorkerRegisteredEvents extends RelayerRegistryEvents {
relayerAddress: string;
workerAddress: string;
}
export interface WorkerUnregisteredEvents extends RelayerRegistryEvents {
relayerAddress: string;
workerAddress: string;
}
export type AllRelayerRegistryEvents = RelayerRegisteredEvents | RelayerUnregisteredEvents | WorkerRegisteredEvents | WorkerUnregisteredEvents;
export interface StakeBurnedEvents extends MinimalEvents {
relayerAddress: string;
amountBurned: string;
instanceAddress: string;
gasFee: string;
relayerFee: string;
timestamp: number;
}
export type RegistersEvents = MinimalEvents & RelayerParams;
export type DepositsEvents = MinimalEvents & {
export interface DepositsEvents extends MinimalEvents {
commitment: string;
leafIndex: number;
timestamp: number;
from: string;
};
export type WithdrawalsEvents = MinimalEvents & {
}
export interface WithdrawalsEvents extends MinimalEvents {
nullifierHash: string;
to: string;
fee: string;
timestamp: number;
};
export type EchoEvents = MinimalEvents & {
}
export interface BaseMultiTornadoEvents {
event: string;
instanceAddress: string;
}
export interface MultiDepositsEvents extends BaseMultiTornadoEvents, DepositsEvents {
}
export interface MultiWithdrawalsEvents extends BaseMultiTornadoEvents, WithdrawalsEvents {
relayerAddress: string;
}
export interface EchoEvents extends MinimalEvents {
address: string;
encryptedAccount: string;
};
export type EncryptedNotesEvents = MinimalEvents & {
}
export interface EncryptedNotesEvents extends MinimalEvents {
encryptedNote: string;
};
}
export interface TransferEvents extends MinimalEvents {
from: string;
to: string;
value: bigint;
}

13
dist/fees.d.ts vendored
View File

@@ -1,4 +1,4 @@
import type { BigNumberish, TransactionLike } from 'ethers';
import type { BigNumberish, JsonRpcApiProvider, TransactionLike } from 'ethers';
import { OvmGasPriceOracle } from './typechain';
/**
* Example:
@@ -19,8 +19,17 @@ export interface RelayerFeeParams {
premiumPercent?: number;
}
export declare class TornadoFeeOracle {
provider: JsonRpcApiProvider;
ovmGasPriceOracle?: OvmGasPriceOracle;
constructor(ovmGasPriceOracle?: OvmGasPriceOracle);
constructor(provider: JsonRpcApiProvider, ovmGasPriceOracle?: OvmGasPriceOracle);
/**
* Calculates Gas Price
* We apply 50% premium of EIP-1559 network fees instead of 100% from ethers.js
* (This should cover up to 4 full blocks which is equivalent of minute)
* (A single block can bump 12.5% of fees, see the methodology https://hackmd.io/@tvanepps/1559-wallets)
* (Still it is recommended to use 100% premium for sending transactions to prevent stucking it)
*/
gasPrice(premium?: number): Promise<bigint>;
/**
* Calculate L1 fee for op-stack chains
*

13
dist/gaszip.d.ts vendored Normal file
View 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;
};

View File

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

3
dist/hasher.d.ts vendored Normal file

File diff suppressed because one or more lines are too long

11
dist/hashes.json vendored Normal file
View File

@@ -0,0 +1,11 @@
{
"dist/index.js": "sha384-txpjgDLxNbeXsLgVCyNAwpaJRS0SmFN/ITfadSo8+xzSvLqwa5bQ9GoxQ1Su8QEr",
"dist/index.mjs": "sha384-CrEHmX4zKIv/68CKWElNzvKk6FWRMMkKV8JmqL1KqYCxO73LPEAjDqxTYpxUuDBy",
"dist/merkleTreeWorker.js": "sha384-XVv9HRGDZlaF0LeEZNQygle31UY6yvIwsZ4GWCTZUX7O/hZ7N5Zwpi3GqnHSBYzW",
"dist/merkleTreeWorker.umd.js": "sha384-e5B65ZZ4IxKVOU1o02K6IL2tjJof20QCcEtD+vKe1cPmyfW2BPCHWDPIbPksIpvJ",
"dist/merkleTreeWorker.umd.min.js": "sha384-AxQv1da+lSi3gMYkdGQuR1WN1+4HB8IT3cPFa17HBj14+ZzdZN6SS1fCw5Izc2rr",
"dist/tornado.umd.js": "sha384-xTUkkUTm3aBsnHCUnVGxRgieAu3z4wCwrKT1DFj8VyCk/eZZO9nq+yP4/McLRfB4",
"dist/tornado.umd.min.js": "sha384-ubqr6m6jEOPf7LQz0pXKmEo7tCCbNUAE+iSZWK6X/f7i4wt14rYW7pUcSzw5glth",
"dist/tornadoContracts.umd.js": "sha384-bFq/cemb0bP0JbIq8p75n0UR8smQ/2Yh69pjegzSuu0upawO3sKOjehY8SjX85Xh",
"dist/tornadoContracts.umd.min.js": "sha384-4ay7cmK0auAgZH1xfAsqyN6GtnHBNNgh9C22qy0rHxKicDzNtTsnNZDbz0qmd9GI"
}

84
dist/idb.d.ts vendored Normal file
View File

@@ -0,0 +1,84 @@
import { OpenDBCallbacks, IDBPDatabase } from 'idb';
import { NetIdType } from './networkConfig';
export declare const INDEX_DB_ERROR = "A mutation operation was attempted on a database that did not allow mutations.";
export interface IDBIndex {
name: string;
unique?: boolean;
}
export interface IDBStores {
name: string;
keyPath?: string;
indexes?: IDBIndex[];
}
export interface IDBConstructor {
dbName: string;
stores?: IDBStores[];
}
export declare class IndexedDB {
dbExists: boolean;
isBlocked: boolean;
options: OpenDBCallbacks<any>;
dbName: string;
dbVersion: number;
db?: IDBPDatabase<any>;
constructor({ dbName, stores }: IDBConstructor);
initDB(): Promise<void>;
_removeExist(): Promise<void>;
getFromIndex<T>({ storeName, indexName, key, }: {
storeName: string;
indexName: string;
key?: string;
}): Promise<T | undefined>;
getAllFromIndex<T>({ storeName, indexName, key, count, }: {
storeName: string;
indexName: string;
key?: string;
count?: number;
}): Promise<T>;
getItem<T>({ storeName, key }: {
storeName: string;
key: string;
}): Promise<T | undefined>;
addItem({ storeName, data, key }: {
storeName: string;
data: any;
key: string;
}): Promise<void>;
putItem({ storeName, data, key }: {
storeName: string;
data: any;
key?: string;
}): Promise<void>;
deleteItem({ storeName, key }: {
storeName: string;
key: string;
}): Promise<void>;
getAll<T>({ storeName }: {
storeName: string;
}): Promise<T>;
/**
* Simple key-value store inspired by idb-keyval package
*/
getValue<T>(key: string): Promise<T | undefined>;
setValue(key: string, data: any): Promise<void>;
delValue(key: string): Promise<void>;
clearStore({ storeName, mode }: {
storeName: string;
mode: IDBTransactionMode;
}): Promise<void>;
createTransactions({ storeName, data, mode, }: {
storeName: string;
data: any;
mode: IDBTransactionMode;
}): Promise<void>;
createMultipleTransactions({ storeName, data, index, mode, }: {
storeName: string;
data: any[];
index?: any;
mode?: IDBTransactionMode;
}): Promise<void>;
}
/**
* Should check if DB is initialized well
*/
export declare function getIndexedDB(netId?: NetIdType): Promise<IndexedDB>;

9
dist/index.d.ts vendored
View File

@@ -1,19 +1,26 @@
export * from './events';
export * from './graphql';
export * from './schemas';
export * from './typechain';
export * from './batch';
export * from './deposits';
export * from './encryptedNotes';
export * from './ens';
export * from './fees';
export * from './gaszip';
export * from './hasher';
export * from './idb';
export * from './ip';
export * from './merkleTree';
export * from './mimc';
export * from './multicall';
export * from './networkConfig';
export * from './pedersen';
export * from './permit';
export * from './prices';
export * from './providers';
export * from './relayerClient';
export * from './tokens';
export * from './tovarishClient';
export * from './utils';
export * from './websnark';
export * from './zip';

12363
dist/index.js vendored

File diff suppressed because one or more lines are too long

12239
dist/index.mjs vendored

File diff suppressed because one or more lines are too long

6
dist/ip.d.ts vendored Normal file
View File

@@ -0,0 +1,6 @@
export interface IPResult {
ip: string;
iso?: string;
tor?: boolean;
}
export declare function fetchIp(ipEcho: string): Promise<IPResult>;

View File

@@ -1,15 +1,15 @@
import { MerkleTree, PartialMerkleTree, Element, TreeEdge } from '@tornado/fixed-merkle-tree';
import { MerkleTree, PartialMerkleTree, Element, TreeEdge } from 'fixed-merkle-tree';
import type { Tornado } from '@tornado/contracts';
import type { DepositType } from './deposits';
import type { DepositsEvents } from './events';
import type { NetIdType } from './networkConfig';
export type MerkleTreeConstructor = DepositType & {
export interface MerkleTreeConstructor extends DepositType {
Tornado: Tornado;
commitmentHex?: string;
merkleTreeHeight?: number;
emptyElement?: string;
merkleWorkerPath?: string;
};
}
export declare class MerkleTreeService {
currency: string;
amount: string;

29702
dist/merkleTreeWorker.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

2
dist/merkleTreeWorker.umd.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,26 @@
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
* @license MIT
*/
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
/*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
/**
* [js-sha3]{@link https://github.com/emn178/js-sha3}
*
* @version 0.8.0
* @author Chen, Yi-Cyuan [emn178@gmail.com]
* @copyright Chen, Yi-Cyuan 2015-2018
* @license MIT
*/

2
dist/mimc.d.ts vendored
View File

@@ -1,5 +1,5 @@
import { MimcSponge } from 'circomlibjs';
import type { Element, HashFunction } from '@tornado/fixed-merkle-tree';
import type { Element, HashFunction } from 'fixed-merkle-tree';
export declare class Mimc {
sponge?: MimcSponge;
hash?: HashFunction<Element>;

View File

@@ -1,3 +1,4 @@
import type { DepositType } from './deposits';
/**
* Type of default supported networks
*/
@@ -7,6 +8,8 @@ export declare enum NetId {
POLYGON = 137,
OPTIMISM = 10,
ARBITRUM = 42161,
BASE = 8453,
BLAST = 81457,
GNOSIS = 100,
AVALANCHE = 43114,
SEPOLIA = 11155111
@@ -16,31 +19,32 @@ export interface RpcUrl {
name: string;
url: string;
}
export type RpcUrls = {
[key in string]: RpcUrl;
};
export interface RpcUrls {
[key: string]: RpcUrl;
}
export interface SubgraphUrl {
name: string;
url: string;
}
export type SubgraphUrls = {
[key in string]: SubgraphUrl;
};
export type TornadoInstance = {
export interface SubgraphUrls {
[key: string]: SubgraphUrl;
}
export interface TornadoInstance {
instanceAddress: {
[key in string]: string;
[key: string]: string;
};
instanceApproval?: boolean;
optionalInstances?: string[];
tokenAddress?: string;
tokenGasLimit?: number;
symbol: string;
decimals: number;
gasLimit?: number;
};
export type TokenInstances = {
[key in string]: TornadoInstance;
};
export type Config = {
}
export interface TokenInstances {
[key: string]: TornadoInstance;
}
export interface Config {
rpcCallRetryAttempt?: number;
gasPrices: {
instant: number;
@@ -57,6 +61,7 @@ export type Config = {
networkName: string;
deployedBlock: number;
rpcUrls: RpcUrls;
stablecoin: string;
multicallContract: string;
routerContract: string;
echoContract: string;
@@ -67,8 +72,6 @@ export type Config = {
registryContract?: string;
aggregatorContract?: string;
reverseRecordsContract?: string;
gasPriceOracleContract?: string;
gasStationApi?: string;
ovmGasPriceOracleContract?: string;
tornadoSubgraph: string;
registrySubgraph?: string;
@@ -76,6 +79,7 @@ export type Config = {
subgraphs: SubgraphUrls;
tokens: TokenInstances;
optionalTokens?: string[];
disabledTokens?: string[];
relayerEnsSubdomain: string;
pollInterval: number;
constants: {
@@ -85,12 +89,15 @@ export type Config = {
REGISTRY_BLOCK?: number;
MINING_BLOCK_TIME?: number;
};
};
export type networkConfig = {
[key in NetIdType]: Config;
};
}
export interface networkConfig {
[key: NetIdType]: Config;
}
export interface SubdomainMap {
[key: NetIdType]: string;
}
export declare const defaultConfig: networkConfig;
export declare const enabledChains: number[];
export declare const enabledChains: NetIdType[];
/**
* Custom config object to extend default config
*
@@ -106,11 +113,16 @@ export declare let customConfig: networkConfig;
export declare function addNetwork(newConfig: networkConfig): void;
export declare function getNetworkConfig(): networkConfig;
export declare function getConfig(netId: NetIdType): Config;
export declare function getInstanceByAddress({ netId, address }: {
netId: NetIdType;
address: string;
}): {
export declare function getActiveTokens(config: Config): string[];
export declare function getActiveTokenInstances(config: Config): TokenInstances;
export declare function getInstanceByAddress(config: Config, address: string): {
amount: string;
currency: string;
symbol: string;
decimals: number;
tokenAddress: string | undefined;
} | undefined;
export declare function getSubdomains(): string[];
export declare function getRelayerEnsSubdomains(): SubdomainMap;
export declare function getMultiInstances(netId: NetIdType, config: Config): {
[key in string]: DepositType;
};

184
dist/permit.d.ts vendored Normal file
View File

@@ -0,0 +1,184 @@
import { ERC20Permit, ERC20Mock, TORN } from '@tornado/contracts';
import { Signature, Signer, TypedDataField } from 'ethers';
export interface PermitValue {
spender: string;
value: bigint;
nonce?: bigint;
deadline?: bigint;
}
export interface PermitCommitments {
denomination: bigint;
commitments: string[];
nonce?: bigint;
deadline?: bigint;
}
export declare const permit2Address = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
/**
* From @uniswap/permit2-sdk ported for ethers.js v6
*/
export interface Witness {
witnessTypeName: string;
witnessType: {
[key: string]: TypedDataField[];
};
witness: any;
}
export declare function getPermitSignature({ Token, signer, spender, value, nonce, deadline, }: PermitValue & {
Token: ERC20Permit | ERC20Mock | TORN;
signer?: Signer;
}): Promise<Signature>;
/**
export async function getPermitCommitmentsSignature({
PermitTornado,
Token,
signer,
denomination,
commitments,
nonce,
}: PermitCommitments & {
PermitTornado: PermitTornado;
Token: ERC20Permit | ERC20Mock | TORN;
signer?: Signer;
}) {
const value = BigInt(commitments.length) * denomination;
const commitmentsHash = solidityPackedKeccak256(['bytes32[]'], [commitments]);
return await getPermitSignature({
Token,
signer,
spender: PermitTornado.target as string,
value,
nonce,
deadline: BigInt(commitmentsHash),
});
}
export async function getPermit2Signature({
Token,
signer,
spender,
value: amount,
nonce,
deadline,
witness,
}: PermitValue & {
Token: BaseContract;
signer?: Signer;
witness?: Witness;
}) {
const sigSigner = (signer || Token.runner) as Signer & { address: string };
const provider = sigSigner.provider as Provider;
const domain = {
name: 'Permit2',
chainId: (await provider.getNetwork()).chainId,
verifyingContract: permit2Address,
};
const types: {
[key: string]: TypedDataField[];
} = !witness
? {
PermitTransferFrom: [
{ name: 'permitted', type: 'TokenPermissions' },
{ name: 'spender', type: 'address' },
{ name: 'nonce', type: 'uint256' },
{ name: 'deadline', type: 'uint256' },
],
TokenPermissions: [
{ name: 'token', type: 'address' },
{ name: 'amount', type: 'uint256' },
],
}
: {
PermitWitnessTransferFrom: [
{ name: 'permitted', type: 'TokenPermissions' },
{ name: 'spender', type: 'address' },
{ name: 'nonce', type: 'uint256' },
{ name: 'deadline', type: 'uint256' },
{ name: 'witness', type: witness.witnessTypeName },
],
TokenPermissions: [
{ name: 'token', type: 'address' },
{ name: 'amount', type: 'uint256' },
],
...witness.witnessType,
};
const values: {
permitted: {
token: string;
amount: bigint;
};
spender: string;
nonce: bigint;
deadline: bigint;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
witness?: any;
} = {
permitted: {
token: Token.target as string,
amount,
},
spender,
// Sorted nonce are not required for Permit2
nonce: nonce || rBigInt(16),
deadline: deadline || MaxUint256,
};
if (witness) {
values.witness = witness.witness;
}
const hash = new TypedDataEncoder(types).hash(values);
const signature = Signature.from(await sigSigner.signTypedData(domain, types, values));
return {
domain,
types,
values,
hash,
signature,
};
}
export async function getPermit2CommitmentsSignature({
PermitTornado,
Token,
signer,
denomination,
commitments,
nonce,
deadline,
}: PermitCommitments & {
PermitTornado: PermitTornado;
Token: BaseContract;
signer?: Signer;
}) {
const value = BigInt(commitments.length) * denomination;
const commitmentsHash = solidityPackedKeccak256(['bytes32[]'], [commitments]);
return await getPermit2Signature({
Token,
signer,
spender: PermitTornado.target as string,
value,
nonce,
deadline,
witness: {
witnessTypeName: 'PermitCommitments',
witnessType: {
PermitCommitments: [
{ name: 'instance', type: 'address' },
{ name: 'commitmentsHash', type: 'bytes32' },
],
},
witness: {
instance: PermitTornado.target,
commitmentsHash,
},
},
});
}
**/

11
dist/prices.d.ts vendored
View File

@@ -1,12 +1,21 @@
import { type Provider } from 'ethers';
import type { OffchainOracle, Multicall } from './typechain';
import { OffchainOracle, Multicall } from './typechain';
import { Call3 } from './multicall';
export declare class TokenPriceOracle {
oracle?: OffchainOracle;
multicall: Multicall;
provider: Provider;
fallbackPrice: bigint;
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: {
tokenAddress: string;
decimals: number;
}[]): Promise<bigint[]>;
fetchEthUSD(stablecoinAddress: string): Promise<number>;
}

37
dist/providers.d.ts vendored
View File

@@ -1,9 +1,6 @@
/// <reference types="node" />
/// <reference types="node" />
/// <reference types="node" />
import type { EventEmitter } from 'stream';
import type { RequestOptions } from 'http';
import { JsonRpcApiProvider, JsonRpcProvider, Wallet, FetchGetUrlFunc, Provider, SigningKey, TransactionRequest, JsonRpcSigner, BrowserProvider, Networkish, Eip1193Provider, VoidSigner, FetchUrlFeeDataNetworkPlugin } from 'ethers';
import { JsonRpcApiProvider, JsonRpcProvider, Wallet, FetchGetUrlFunc, Provider, SigningKey, TransactionRequest, JsonRpcSigner, BrowserProvider, Networkish, Eip1193Provider, VoidSigner, FetchCancelSignal } from 'ethers';
import type { RequestInfo, RequestInit, Response, HeadersInit } from 'node-fetch';
import type { Config, NetIdType } from './networkConfig';
declare global {
@@ -11,8 +8,7 @@ declare global {
ethereum?: Eip1193Provider & EventEmitter;
}
}
export declare const defaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; rv:109.0) Gecko/20100101 Firefox/115.0";
export declare const fetch: nodeFetch;
export declare const defaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0";
export type nodeFetch = (url: RequestInfo, init?: RequestInit) => Promise<Response>;
export type fetchDataOptions = RequestInit & {
headers?: HeadersInit | any;
@@ -24,6 +20,7 @@ export type fetchDataOptions = RequestInit & {
torPort?: number;
debug?: Function;
returnResponse?: boolean;
cancelSignal?: FetchCancelSignal;
};
export type NodeAgent = RequestOptions['agent'] | ((parsedUrl: URL) => RequestOptions['agent']);
export declare function getHttpAgent({ fetchUrl, proxyUrl, torPort, retry, }: {
@@ -35,57 +32,57 @@ export declare function getHttpAgent({ fetchUrl, proxyUrl, torPort, retry, }: {
export declare function fetchData(url: string, options?: fetchDataOptions): Promise<any>;
export declare const fetchGetUrlFunc: (options?: fetchDataOptions) => FetchGetUrlFunc;
export type getProviderOptions = fetchDataOptions & {
netId?: NetIdType;
pollingInterval?: number;
gasPriceOracle?: string;
gasStationApi?: string;
};
export declare function getGasOraclePlugin(networkKey: string, fetchOptions?: getProviderOptions): FetchUrlFeeDataNetworkPlugin;
export declare function getProvider(rpcUrl: string, fetchOptions?: getProviderOptions): Promise<JsonRpcProvider>;
export declare function getProviderWithNetId(netId: NetIdType, rpcUrl: string, config: Config, fetchOptions?: getProviderOptions): JsonRpcProvider;
export declare const populateTransaction: (signer: TornadoWallet | TornadoVoidSigner | TornadoRpcSigner, tx: TransactionRequest) => Promise<TransactionRequest>;
export type TornadoWalletOptions = {
export interface TornadoWalletOptions {
gasPriceBump?: number;
gasLimitBump?: number;
gasFailover?: boolean;
bumpNonce?: boolean;
};
readonlyProvider?: Provider;
}
export declare class TornadoWallet extends Wallet {
nonce?: number | null;
nonce?: number;
gasPriceBump: number;
gasLimitBump: number;
gasFailover: boolean;
bumpNonce: boolean;
constructor(key: string | SigningKey, provider?: null | Provider, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce }?: TornadoWalletOptions);
constructor(key: string | SigningKey, provider?: Provider, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce }?: TornadoWalletOptions);
static fromMnemonic(mneomnic: string, provider: Provider, index?: number, options?: TornadoWalletOptions): TornadoWallet;
populateTransaction(tx: TransactionRequest): Promise<import("ethers").TransactionLike<string>>;
}
export declare class TornadoVoidSigner extends VoidSigner {
nonce?: number | null;
nonce?: number;
gasPriceBump: number;
gasLimitBump: number;
gasFailover: boolean;
bumpNonce: boolean;
constructor(address: string, provider?: null | Provider, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce }?: TornadoWalletOptions);
constructor(address: string, provider?: Provider, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce }?: TornadoWalletOptions);
populateTransaction(tx: TransactionRequest): Promise<import("ethers").TransactionLike<string>>;
}
export declare class TornadoRpcSigner extends JsonRpcSigner {
nonce?: number | null;
nonce?: number;
gasPriceBump: number;
gasLimitBump: number;
gasFailover: boolean;
bumpNonce: boolean;
constructor(provider: JsonRpcApiProvider, address: string, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce }?: TornadoWalletOptions);
readonlyProvider?: Provider;
constructor(provider: JsonRpcApiProvider, address: string, { gasPriceBump, gasLimitBump, gasFailover, bumpNonce, readonlyProvider }?: TornadoWalletOptions);
sendUncheckedTransaction(tx: TransactionRequest): Promise<string>;
}
export type connectWalletFunc = (...args: any[]) => Promise<void>;
export type handleWalletFunc = (...args: any[]) => void;
export type TornadoBrowserProviderOptions = TornadoWalletOptions & {
webChainId?: NetIdType;
export interface TornadoBrowserProviderOptions extends TornadoWalletOptions {
netId?: NetIdType;
connectWallet?: connectWalletFunc;
handleNetworkChanges?: handleWalletFunc;
handleAccountChanges?: handleWalletFunc;
handleAccountDisconnect?: handleWalletFunc;
};
}
export declare class TornadoBrowserProvider extends BrowserProvider {
options?: TornadoBrowserProviderOptions;
constructor(ethereum: Eip1193Provider, network?: Networkish, options?: TornadoBrowserProviderOptions);

View File

@@ -1,19 +1,24 @@
import type { Aggregator } from '@tornado/contracts';
import type { RelayerStructOutput } from '@tornado/contracts/dist/contracts/Governance/Aggregator/Aggregator';
import { NetIdType, Config } from './networkConfig';
import { fetchDataOptions } from './providers';
import type { snarkProofs } from './websnark';
import type { CachedRelayerInfo } from './events';
export declare const MIN_FEE = 0.1;
export declare const MAX_FEE = 0.9;
export declare const MIN_STAKE_BALANCE: bigint;
export interface RelayerParams {
ensName: string;
relayerAddress?: string;
relayerAddress: string;
}
export interface Relayer {
/**
* Info from relayer status
*/
export interface RelayerInfo extends RelayerParams {
netId: NetIdType;
url: string;
hostname: string;
rewardAccount: string;
instances: string[];
stakeBalance?: string;
gasPrice?: number;
ethPrices?: {
[key in string]: string;
@@ -21,16 +26,12 @@ export interface Relayer {
currentQueue: number;
tornadoServiceFee: number;
}
export type RelayerInfo = Relayer & {
ensName: string;
stakeBalance: bigint;
relayerAddress: string;
};
export type RelayerError = {
export interface RelayerError {
hostname: string;
relayerAddress?: string;
errorMessage?: string;
};
hasError: boolean;
}
export interface RelayerStatus {
url: string;
rewardAccount: string;
@@ -62,6 +63,9 @@ export interface RelayerStatus {
};
currentQueue: number;
}
export interface TornadoWithdrawParams extends snarkProofs {
contract: string;
}
export interface RelayerTornadoWithdraw {
id?: string;
error?: string;
@@ -78,51 +82,66 @@ export interface RelayerTornadoJobs {
confirmations?: number;
failedReason?: string;
}
/**
const semVerRegex =
/^(?<major>0|[1-9]\d*)\.(?<minor>0|[1-9]\d*)\.(?<patch>0|[1-9]\d*)(?:-(?<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
export interface semanticVersion {
major: string;
minor: string;
patch: string;
prerelease?: string;
buildmetadata?: string;
major: string;
minor: string;
patch: string;
prerelease?: string;
buildmetadata?: string;
}
export declare function parseSemanticVersion(version: string): semanticVersion;
export declare function isRelayerUpdated(relayerVersion: string, netId: NetIdType): boolean;
export declare function calculateScore({ stakeBalance, tornadoServiceFee }: RelayerInfo, minFee?: number, maxFee?: number): bigint;
export function parseSemanticVersion(version: string) {
const { groups } = semVerRegex.exec(version) as RegExpExecArray;
return groups as unknown as semanticVersion;
}
export function isRelayerUpdated(relayerVersion: string, netId: NetIdType) {
const { major, patch, prerelease } = parseSemanticVersion(relayerVersion);
// Save backwards compatibility with V4 relayers for Ethereum Mainnet
const requiredMajor = netId === NetId.MAINNET ? '4' : '5';
const isUpdatedMajor = major === requiredMajor;
if (prerelease) return false;
return isUpdatedMajor && (Number(patch) >= 5 || netId !== NetId.MAINNET); // Patch checking - also backwards compatibility for Mainnet
}
**/
export declare function calculateScore({ stakeBalance, tornadoServiceFee }: RelayerInfo): bigint;
export declare function getWeightRandom(weightsScores: bigint[], random: bigint): number;
export type RelayerInstanceList = {
[key in string]: {
export interface RelayerInstanceList {
[key: string]: {
instanceAddress: {
[key in string]: string;
[key: string]: string;
};
};
};
}
export declare function getSupportedInstances(instanceList: RelayerInstanceList): string[];
export declare function pickWeightedRandomRelayer(relayers: RelayerInfo[], netId: NetIdType): RelayerInfo;
export declare function pickWeightedRandomRelayer(relayers: RelayerInfo[]): RelayerInfo;
export interface RelayerClientConstructor {
netId: NetIdType;
config: Config;
Aggregator: Aggregator;
fetchDataOptions?: fetchDataOptions;
}
export type RelayerClientWithdraw = snarkProofs & {
contract: string;
};
export declare class RelayerClient {
netId: NetIdType;
config: Config;
Aggregator: Aggregator;
selectedRelayer?: Relayer;
selectedRelayer?: RelayerInfo;
fetchDataOptions?: fetchDataOptions;
constructor({ netId, config, Aggregator, fetchDataOptions }: RelayerClientConstructor);
askRelayerStatus({ hostname, relayerAddress, }: {
hostname: string;
tovarish: boolean;
constructor({ netId, config, fetchDataOptions }: RelayerClientConstructor);
askRelayerStatus({ hostname, url, relayerAddress, }: {
hostname?: string;
url?: string;
relayerAddress?: string;
}): Promise<RelayerStatus>;
filterRelayer(curr: RelayerStructOutput, relayer: RelayerParams, subdomains: string[], debugRelayer?: boolean): Promise<RelayerInfo | RelayerError>;
getValidRelayers(relayers: RelayerParams[], subdomains: string[], debugRelayer?: boolean): Promise<{
filterRelayer(relayer: CachedRelayerInfo): Promise<RelayerInfo | RelayerError | undefined>;
getValidRelayers(relayers: CachedRelayerInfo[]): Promise<{
validRelayers: RelayerInfo[];
invalidRelayers: RelayerError[];
}>;
pickWeightedRandomRelayer(relayers: RelayerInfo[]): RelayerInfo;
tornadoWithdraw({ contract, proof, args }: RelayerClientWithdraw): Promise<void>;
tornadoWithdraw({ contract, proof, args }: TornadoWithdrawParams, callback?: (jobResp: RelayerTornadoWithdraw | RelayerTornadoJobs) => void): Promise<void>;
}

2
dist/schemas/ajv.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
import Ajv from 'ajv';
export declare const ajv: Ajv;

492
dist/schemas/events.d.ts vendored Normal file
View File

@@ -0,0 +1,492 @@
export declare const governanceEventsSchema: {
readonly type: "array";
readonly items: {
readonly anyOf: readonly [{
readonly type: "object";
readonly properties: {
readonly event: {
readonly type: "string";
};
readonly id: {
readonly type: "number";
};
readonly proposer: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly target: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly startTime: {
readonly type: "number";
};
readonly endTime: {
readonly type: "number";
};
readonly description: {
readonly type: "string";
};
readonly blockNumber: {
readonly type: "number";
};
readonly logIndex: {
readonly type: "number";
};
readonly transactionHash: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
};
readonly required: readonly [...string[], "event", "id", "proposer", "target", "startTime", "endTime", "description"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly properties: {
readonly event: {
readonly type: "string";
};
readonly proposalId: {
readonly type: "number";
};
readonly voter: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly support: {
readonly type: "boolean";
};
readonly votes: {
readonly type: "string";
};
readonly from: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly input: {
readonly type: "string";
};
readonly blockNumber: {
readonly type: "number";
};
readonly logIndex: {
readonly type: "number";
};
readonly transactionHash: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
};
readonly required: readonly [...string[], "event", "proposalId", "voter", "support", "votes", "from", "input"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly properties: {
readonly event: {
readonly type: "string";
};
readonly account: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly delegateTo: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly blockNumber: {
readonly type: "number";
};
readonly logIndex: {
readonly type: "number";
};
readonly transactionHash: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
};
readonly required: readonly [...string[], "account", "delegateTo"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly properties: {
readonly event: {
readonly type: "string";
};
readonly account: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly delegateFrom: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly blockNumber: {
readonly type: "number";
};
readonly logIndex: {
readonly type: "number";
};
readonly transactionHash: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
};
readonly required: readonly [...string[], "account", "delegateFrom"];
readonly additionalProperties: false;
}];
};
};
export declare const relayerRegistryEventsSchema: {
readonly type: "array";
readonly items: {
readonly anyOf: readonly [{
readonly type: "object";
readonly properties: {
readonly event: {
readonly type: "string";
};
readonly ensName: {
readonly type: "string";
};
readonly relayerAddress: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly ensHash: {
readonly type: "string";
};
readonly stakedAmount: {
readonly type: "string";
};
readonly blockNumber: {
readonly type: "number";
};
readonly logIndex: {
readonly type: "number";
};
readonly transactionHash: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
};
readonly required: readonly [...string[], "event", "ensName", "relayerAddress", "ensHash", "stakedAmount"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly properties: {
readonly event: {
readonly type: "string";
};
readonly relayerAddress: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly blockNumber: {
readonly type: "number";
};
readonly logIndex: {
readonly type: "number";
};
readonly transactionHash: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
};
readonly required: readonly [...string[], "event", "relayerAddress"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly properties: {
readonly event: {
readonly type: "string";
};
readonly relayerAddress: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly workerAddress: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly blockNumber: {
readonly type: "number";
};
readonly logIndex: {
readonly type: "number";
};
readonly transactionHash: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
};
readonly required: readonly [...string[], "event", "relayerAddress", "workerAddress"];
readonly additionalProperties: false;
}];
};
};
export declare const stakeBurnedEventsSchema: {
readonly type: "array";
readonly items: {
readonly type: "object";
readonly properties: {
readonly relayerAddress: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly amountBurned: {
readonly type: "string";
readonly BN: true;
};
readonly instanceAddress: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly gasFee: {
readonly type: "string";
readonly BN: true;
};
readonly relayerFee: {
readonly type: "string";
readonly BN: true;
};
readonly timestamp: {
readonly type: "number";
};
readonly blockNumber: {
readonly type: "number";
};
readonly logIndex: {
readonly type: "number";
};
readonly transactionHash: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
};
readonly required: readonly [...string[], "relayerAddress", "amountBurned", "instanceAddress", "gasFee", "relayerFee", "timestamp"];
readonly additionalProperties: false;
};
};
export declare const depositsEventsSchema: {
readonly type: "array";
readonly items: {
readonly type: "object";
readonly properties: {
readonly commitment: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
readonly leafIndex: {
readonly type: "number";
};
readonly timestamp: {
readonly type: "number";
};
readonly from: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly blockNumber: {
readonly type: "number";
};
readonly logIndex: {
readonly type: "number";
};
readonly transactionHash: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
};
readonly required: readonly [...string[], "commitment", "leafIndex", "timestamp", "from"];
readonly additionalProperties: false;
};
};
export declare const withdrawalsEventsSchema: {
readonly type: "array";
readonly items: {
readonly type: "object";
readonly properties: {
readonly nullifierHash: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
readonly to: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly fee: {
readonly type: "string";
readonly BN: true;
};
readonly timestamp: {
readonly type: "number";
};
readonly blockNumber: {
readonly type: "number";
};
readonly logIndex: {
readonly type: "number";
};
readonly transactionHash: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
};
readonly required: readonly [...string[], "nullifierHash", "to", "fee", "timestamp"];
readonly additionalProperties: false;
};
};
export declare const tornadoEventsSchema: {
readonly type: "array";
readonly items: {
readonly anyOf: readonly [{
readonly type: "object";
readonly properties: {
readonly event: {
readonly type: "string";
};
readonly instanceAddress: {
readonly type: "string";
};
readonly commitment: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
readonly leafIndex: {
readonly type: "number";
};
readonly timestamp: {
readonly type: "number";
};
readonly from: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly blockNumber: {
readonly type: "number";
};
readonly logIndex: {
readonly type: "number";
};
readonly transactionHash: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
};
readonly required: readonly [...string[], "event", "instanceAddress", "commitment", "leafIndex", "timestamp", "from"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly properties: {
readonly event: {
readonly type: "string";
};
readonly instanceAddress: {
readonly type: "string";
};
readonly nullifierHash: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
readonly to: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly relayerAddress: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly fee: {
readonly type: "string";
readonly BN: true;
};
readonly timestamp: {
readonly type: "number";
};
readonly blockNumber: {
readonly type: "number";
};
readonly logIndex: {
readonly type: "number";
};
readonly transactionHash: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
};
readonly required: readonly [...string[], "event", "instanceAddress", "nullifierHash", "to", "relayerAddress", "fee", "timestamp"];
readonly additionalProperties: false;
}];
};
};
export declare const echoEventsSchema: {
readonly type: "array";
readonly items: {
readonly type: "object";
readonly properties: {
readonly address: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
readonly encryptedAccount: {
readonly type: "string";
};
readonly blockNumber: {
readonly type: "number";
};
readonly logIndex: {
readonly type: "number";
};
readonly transactionHash: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
};
readonly required: readonly [...string[], "address", "encryptedAccount"];
readonly additionalProperties: false;
};
};
export declare const encryptedNotesSchema: {
readonly type: "array";
readonly items: {
readonly type: "object";
readonly properties: {
readonly encryptedNote: {
readonly type: "string";
};
readonly blockNumber: {
readonly type: "number";
};
readonly logIndex: {
readonly type: "number";
};
readonly transactionHash: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
};
readonly required: readonly [...string[], "encryptedNote"];
readonly additionalProperties: false;
};
};
export declare function getEventsSchemaValidator(type: string): import("ajv").ValidateFunction<unknown>;

View File

@@ -1,4 +1,5 @@
import Ajv from 'ajv';
export declare const ajv: Ajv;
export * from './ajv';
export * from './events';
export * from './status';
export * from './jobs';
export * from './types';

View File

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

View File

@@ -1,15 +1,16 @@
import { Config, NetIdType } from '../networkConfig';
export type statusInstanceType = {
import { addressSchemaType, bnSchemaType } from '.';
export interface statusInstanceType {
type: string;
properties: {
instanceAddress: {
type: string;
properties: {
[key in string]: typeof addressType;
[key in string]: typeof addressSchemaType;
};
required: string[];
};
tokenAddress?: typeof addressType;
tokenAddress?: typeof addressSchemaType;
symbol?: {
enum: string[];
};
@@ -18,25 +19,25 @@ export type statusInstanceType = {
};
};
required: string[];
};
export type statusInstancesType = {
}
export interface statusInstancesType {
type: string;
properties: {
[key in string]: statusInstanceType;
};
required: string[];
};
export type statusEthPricesType = {
}
export interface statusEthPricesType {
type: string;
properties: {
[key in string]: typeof bnType;
[key in string]: typeof bnSchemaType;
};
required?: string[];
};
export type statusSchema = {
}
export interface statusSchema {
type: string;
properties: {
rewardAccount: typeof addressType;
rewardAccount: typeof addressSchemaType;
instances?: statusInstancesType;
gasPrices: {
type: string;
@@ -56,9 +57,13 @@ export type statusSchema = {
maximum: number;
minimum: number;
};
latestBlock?: {
latestBlock: {
type: string;
};
latestBalance: {
type: string;
BN: boolean;
};
version: {
type: string;
};
@@ -74,19 +79,28 @@ export type statusSchema = {
};
required: string[];
};
syncStatus: {
type: string;
properties: {
events: {
type: string;
};
tokenPrice: {
type: string;
};
gasPrice: {
type: string;
};
};
required: string[];
};
onSyncEvents: {
type: string;
};
currentQueue: {
type: string;
};
};
required: string[];
};
declare const addressType: {
type: string;
pattern: string;
};
declare const bnType: {
type: string;
BN: boolean;
};
export declare function getStatusSchema(netId: NetIdType, config: Config): statusSchema;
export {};
}
export declare function getStatusSchema(netId: NetIdType, config: Config, tovarish: boolean): statusSchema;

22
dist/schemas/types.d.ts vendored Normal file
View File

@@ -0,0 +1,22 @@
export declare const addressSchemaType: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{40}$";
readonly isAddress: true;
};
export declare const bnSchemaType: {
readonly type: "string";
readonly BN: true;
};
export declare const proofSchemaType: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{512}$";
};
export declare const bytes32SchemaType: {
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};
export declare const bytes32BNSchemaType: {
readonly BN: true;
readonly type: "string";
readonly pattern: "^0x[a-fA-F0-9]{64}$";
};

File diff suppressed because one or more lines are too long

8
dist/tornado.umd.min.js vendored Normal file

File diff suppressed because one or more lines are too long

34
dist/tornado.umd.min.js.LICENSE.txt vendored Normal file
View File

@@ -0,0 +1,34 @@
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
* @license MIT
*/
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
/*! MIT License. Copyright 2015-2022 Richard Moore <me@ricmoo.com>. See LICENSE.txt. */
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
/*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
/*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) */
/**
* [js-sha3]{@link https://github.com/emn178/js-sha3}
*
* @version 0.8.0
* @author Chen, Yi-Cyuan [emn178@gmail.com]
* @copyright Chen, Yi-Cyuan 2015-2018
* @license MIT
*/

45121
dist/tornadoContracts.umd.js vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/tornadoContracts.umd.min.js vendored Normal file

File diff suppressed because one or more lines are too long

71
dist/tovarishClient.d.ts vendored Normal file
View File

@@ -0,0 +1,71 @@
import { RelayerClient, RelayerClientConstructor, RelayerError, RelayerInfo, RelayerStatus } from './relayerClient';
import { CachedRelayerInfo, MinimalEvents } from './events';
export declare const MAX_TOVARISH_EVENTS = 5000;
export interface EventsStatus {
events: number;
lastBlock: number;
}
export interface TovarishEventsStatus {
governance?: EventsStatus;
registry?: EventsStatus;
revenue?: EventsStatus;
echo: EventsStatus;
encrypted_notes: EventsStatus;
tornado: EventsStatus;
}
export interface TovarishSyncStatus {
events: boolean;
tokenPrice: boolean;
gasPrice: boolean;
}
export interface TovarishStatus extends RelayerStatus {
latestBalance: string;
events: TovarishEventsStatus;
syncStatus: TovarishSyncStatus;
onSyncEvents: boolean;
}
export interface TovarishInfo extends RelayerInfo {
latestBlock: number;
latestBalance: string;
version: string;
events: TovarishEventsStatus;
syncStatus: TovarishSyncStatus;
}
export interface TovarishEventsQuery {
type: string;
currency?: string;
amount?: string;
fromBlock: number;
recent?: boolean;
}
export interface BaseTovarishEvents<T> {
events: T[];
lastSyncBlock: number;
}
export declare class TovarishClient extends RelayerClient {
selectedRelayer?: TovarishInfo;
constructor(clientConstructor: RelayerClientConstructor);
askRelayerStatus({ hostname, url, relayerAddress, }: {
hostname?: string;
url?: string;
relayerAddress?: string;
}): 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>;
getValidRelayers(relayers: CachedRelayerInfo[]): Promise<{
validRelayers: TovarishInfo[];
invalidRelayers: RelayerError[];
}>;
getTovarishRelayers(relayers: CachedRelayerInfo[]): Promise<{
validRelayers: TovarishInfo[];
invalidRelayers: RelayerError[];
}>;
getEvents<T extends MinimalEvents>({ type, currency, amount, fromBlock, recent, }: TovarishEventsQuery): Promise<BaseTovarishEvents<T>>;
}

847
dist/typechain/ENSNameWrapper.d.ts vendored Normal file
View File

@@ -0,0 +1,847 @@
import type { BaseContract, BigNumberish, BytesLike, FunctionFragment, Result, Interface, EventFragment, AddressLike, ContractRunner, ContractMethod, Listener } from "ethers";
import type { TypedContractEvent, TypedDeferredTopicFilter, TypedEventLog, TypedLogDescription, TypedListener, TypedContractMethod } from "./common";
export interface ENSNameWrapperInterface extends Interface {
getFunction(nameOrSignature: "_tokens" | "allFusesBurned" | "approve" | "balanceOf" | "balanceOfBatch" | "canExtendSubnames" | "canModifyName" | "controllers" | "ens" | "extendExpiry" | "getApproved" | "getData" | "isApprovedForAll" | "isWrapped(bytes32,bytes32)" | "isWrapped(bytes32)" | "metadataService" | "name" | "names" | "onERC721Received" | "owner" | "ownerOf" | "recoverFunds" | "registerAndWrapETH2LD" | "registrar" | "renew" | "renounceOwnership" | "safeBatchTransferFrom" | "safeTransferFrom" | "setApprovalForAll" | "setChildFuses" | "setController" | "setFuses" | "setMetadataService" | "setRecord" | "setResolver" | "setSubnodeOwner" | "setSubnodeRecord" | "setTTL" | "setUpgradeContract" | "supportsInterface" | "transferOwnership" | "unwrap" | "unwrapETH2LD" | "upgrade" | "upgradeContract" | "uri" | "wrap" | "wrapETH2LD"): FunctionFragment;
getEvent(nameOrSignatureOrTopic: "Approval" | "ApprovalForAll" | "ControllerChanged" | "ExpiryExtended" | "FusesSet" | "NameUnwrapped" | "NameWrapped" | "OwnershipTransferred" | "TransferBatch" | "TransferSingle" | "URI"): EventFragment;
encodeFunctionData(functionFragment: "_tokens", values: [BigNumberish]): string;
encodeFunctionData(functionFragment: "allFusesBurned", values: [BytesLike, BigNumberish]): string;
encodeFunctionData(functionFragment: "approve", values: [AddressLike, BigNumberish]): string;
encodeFunctionData(functionFragment: "balanceOf", values: [AddressLike, BigNumberish]): string;
encodeFunctionData(functionFragment: "balanceOfBatch", values: [AddressLike[], BigNumberish[]]): string;
encodeFunctionData(functionFragment: "canExtendSubnames", values: [BytesLike, AddressLike]): string;
encodeFunctionData(functionFragment: "canModifyName", values: [BytesLike, AddressLike]): string;
encodeFunctionData(functionFragment: "controllers", values: [AddressLike]): string;
encodeFunctionData(functionFragment: "ens", values?: undefined): string;
encodeFunctionData(functionFragment: "extendExpiry", values: [BytesLike, BytesLike, BigNumberish]): string;
encodeFunctionData(functionFragment: "getApproved", values: [BigNumberish]): string;
encodeFunctionData(functionFragment: "getData", values: [BigNumberish]): string;
encodeFunctionData(functionFragment: "isApprovedForAll", values: [AddressLike, AddressLike]): string;
encodeFunctionData(functionFragment: "isWrapped(bytes32,bytes32)", values: [BytesLike, BytesLike]): string;
encodeFunctionData(functionFragment: "isWrapped(bytes32)", values: [BytesLike]): string;
encodeFunctionData(functionFragment: "metadataService", values?: undefined): string;
encodeFunctionData(functionFragment: "name", values?: undefined): string;
encodeFunctionData(functionFragment: "names", values: [BytesLike]): string;
encodeFunctionData(functionFragment: "onERC721Received", values: [AddressLike, AddressLike, BigNumberish, BytesLike]): string;
encodeFunctionData(functionFragment: "owner", values?: undefined): string;
encodeFunctionData(functionFragment: "ownerOf", values: [BigNumberish]): string;
encodeFunctionData(functionFragment: "recoverFunds", values: [AddressLike, AddressLike, BigNumberish]): string;
encodeFunctionData(functionFragment: "registerAndWrapETH2LD", values: [string, AddressLike, BigNumberish, AddressLike, BigNumberish]): string;
encodeFunctionData(functionFragment: "registrar", values?: undefined): string;
encodeFunctionData(functionFragment: "renew", values: [BigNumberish, BigNumberish]): string;
encodeFunctionData(functionFragment: "renounceOwnership", values?: undefined): string;
encodeFunctionData(functionFragment: "safeBatchTransferFrom", values: [
AddressLike,
AddressLike,
BigNumberish[],
BigNumberish[],
BytesLike
]): string;
encodeFunctionData(functionFragment: "safeTransferFrom", values: [AddressLike, AddressLike, BigNumberish, BigNumberish, BytesLike]): string;
encodeFunctionData(functionFragment: "setApprovalForAll", values: [AddressLike, boolean]): string;
encodeFunctionData(functionFragment: "setChildFuses", values: [BytesLike, BytesLike, BigNumberish, BigNumberish]): string;
encodeFunctionData(functionFragment: "setController", values: [AddressLike, boolean]): string;
encodeFunctionData(functionFragment: "setFuses", values: [BytesLike, BigNumberish]): string;
encodeFunctionData(functionFragment: "setMetadataService", values: [AddressLike]): string;
encodeFunctionData(functionFragment: "setRecord", values: [BytesLike, AddressLike, AddressLike, BigNumberish]): string;
encodeFunctionData(functionFragment: "setResolver", values: [BytesLike, AddressLike]): string;
encodeFunctionData(functionFragment: "setSubnodeOwner", values: [BytesLike, string, AddressLike, BigNumberish, BigNumberish]): string;
encodeFunctionData(functionFragment: "setSubnodeRecord", values: [
BytesLike,
string,
AddressLike,
AddressLike,
BigNumberish,
BigNumberish,
BigNumberish
]): string;
encodeFunctionData(functionFragment: "setTTL", values: [BytesLike, BigNumberish]): string;
encodeFunctionData(functionFragment: "setUpgradeContract", values: [AddressLike]): string;
encodeFunctionData(functionFragment: "supportsInterface", values: [BytesLike]): string;
encodeFunctionData(functionFragment: "transferOwnership", values: [AddressLike]): string;
encodeFunctionData(functionFragment: "unwrap", values: [BytesLike, BytesLike, AddressLike]): string;
encodeFunctionData(functionFragment: "unwrapETH2LD", values: [BytesLike, AddressLike, AddressLike]): string;
encodeFunctionData(functionFragment: "upgrade", values: [BytesLike, BytesLike]): string;
encodeFunctionData(functionFragment: "upgradeContract", values?: undefined): string;
encodeFunctionData(functionFragment: "uri", values: [BigNumberish]): string;
encodeFunctionData(functionFragment: "wrap", values: [BytesLike, AddressLike, AddressLike]): string;
encodeFunctionData(functionFragment: "wrapETH2LD", values: [string, AddressLike, BigNumberish, AddressLike]): string;
decodeFunctionResult(functionFragment: "_tokens", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "allFusesBurned", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "approve", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "balanceOf", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "balanceOfBatch", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "canExtendSubnames", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "canModifyName", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "controllers", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "ens", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "extendExpiry", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "getApproved", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "getData", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "isApprovedForAll", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "isWrapped(bytes32,bytes32)", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "isWrapped(bytes32)", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "metadataService", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "name", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "names", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "onERC721Received", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "owner", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "ownerOf", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "recoverFunds", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "registerAndWrapETH2LD", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "registrar", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "renew", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "renounceOwnership", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "safeBatchTransferFrom", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "safeTransferFrom", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setApprovalForAll", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setChildFuses", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setController", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setFuses", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setMetadataService", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setRecord", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setResolver", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setSubnodeOwner", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setSubnodeRecord", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setTTL", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setUpgradeContract", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "supportsInterface", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "transferOwnership", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "unwrap", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "unwrapETH2LD", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "upgrade", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "upgradeContract", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "uri", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "wrap", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "wrapETH2LD", data: BytesLike): Result;
}
export declare namespace ApprovalEvent {
type InputTuple = [
owner: AddressLike,
approved: AddressLike,
tokenId: BigNumberish
];
type OutputTuple = [owner: string, approved: string, tokenId: bigint];
interface OutputObject {
owner: string;
approved: string;
tokenId: bigint;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace ApprovalForAllEvent {
type InputTuple = [
account: AddressLike,
operator: AddressLike,
approved: boolean
];
type OutputTuple = [
account: string,
operator: string,
approved: boolean
];
interface OutputObject {
account: string;
operator: string;
approved: boolean;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace ControllerChangedEvent {
type InputTuple = [controller: AddressLike, active: boolean];
type OutputTuple = [controller: string, active: boolean];
interface OutputObject {
controller: string;
active: boolean;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace ExpiryExtendedEvent {
type InputTuple = [node: BytesLike, expiry: BigNumberish];
type OutputTuple = [node: string, expiry: bigint];
interface OutputObject {
node: string;
expiry: bigint;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace FusesSetEvent {
type InputTuple = [node: BytesLike, fuses: BigNumberish];
type OutputTuple = [node: string, fuses: bigint];
interface OutputObject {
node: string;
fuses: bigint;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace NameUnwrappedEvent {
type InputTuple = [node: BytesLike, owner: AddressLike];
type OutputTuple = [node: string, owner: string];
interface OutputObject {
node: string;
owner: string;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace NameWrappedEvent {
type InputTuple = [
node: BytesLike,
name: BytesLike,
owner: AddressLike,
fuses: BigNumberish,
expiry: BigNumberish
];
type OutputTuple = [
node: string,
name: string,
owner: string,
fuses: bigint,
expiry: bigint
];
interface OutputObject {
node: string;
name: string;
owner: string;
fuses: bigint;
expiry: bigint;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace OwnershipTransferredEvent {
type InputTuple = [previousOwner: AddressLike, newOwner: AddressLike];
type OutputTuple = [previousOwner: string, newOwner: string];
interface OutputObject {
previousOwner: string;
newOwner: string;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace TransferBatchEvent {
type InputTuple = [
operator: AddressLike,
from: AddressLike,
to: AddressLike,
ids: BigNumberish[],
values: BigNumberish[]
];
type OutputTuple = [
operator: string,
from: string,
to: string,
ids: bigint[],
values: bigint[]
];
interface OutputObject {
operator: string;
from: string;
to: string;
ids: bigint[];
values: bigint[];
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace TransferSingleEvent {
type InputTuple = [
operator: AddressLike,
from: AddressLike,
to: AddressLike,
id: BigNumberish,
value: BigNumberish
];
type OutputTuple = [
operator: string,
from: string,
to: string,
id: bigint,
value: bigint
];
interface OutputObject {
operator: string;
from: string;
to: string;
id: bigint;
value: bigint;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace URIEvent {
type InputTuple = [value: string, id: BigNumberish];
type OutputTuple = [value: string, id: bigint];
interface OutputObject {
value: string;
id: bigint;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export interface ENSNameWrapper extends BaseContract {
connect(runner?: ContractRunner | null): ENSNameWrapper;
waitForDeployment(): Promise<this>;
interface: ENSNameWrapperInterface;
queryFilter<TCEvent extends TypedContractEvent>(event: TCEvent, fromBlockOrBlockhash?: string | number | undefined, toBlock?: string | number | undefined): Promise<Array<TypedEventLog<TCEvent>>>;
queryFilter<TCEvent extends TypedContractEvent>(filter: TypedDeferredTopicFilter<TCEvent>, fromBlockOrBlockhash?: string | number | undefined, toBlock?: string | number | undefined): Promise<Array<TypedEventLog<TCEvent>>>;
on<TCEvent extends TypedContractEvent>(event: TCEvent, listener: TypedListener<TCEvent>): Promise<this>;
on<TCEvent extends TypedContractEvent>(filter: TypedDeferredTopicFilter<TCEvent>, listener: TypedListener<TCEvent>): Promise<this>;
once<TCEvent extends TypedContractEvent>(event: TCEvent, listener: TypedListener<TCEvent>): Promise<this>;
once<TCEvent extends TypedContractEvent>(filter: TypedDeferredTopicFilter<TCEvent>, listener: TypedListener<TCEvent>): Promise<this>;
listeners<TCEvent extends TypedContractEvent>(event: TCEvent): Promise<Array<TypedListener<TCEvent>>>;
listeners(eventName?: string): Promise<Array<Listener>>;
removeAllListeners<TCEvent extends TypedContractEvent>(event?: TCEvent): Promise<this>;
_tokens: TypedContractMethod<[arg0: BigNumberish], [bigint], "view">;
allFusesBurned: TypedContractMethod<[
node: BytesLike,
fuseMask: BigNumberish
], [
boolean
], "view">;
approve: TypedContractMethod<[
to: AddressLike,
tokenId: BigNumberish
], [
void
], "nonpayable">;
balanceOf: TypedContractMethod<[
account: AddressLike,
id: BigNumberish
], [
bigint
], "view">;
balanceOfBatch: TypedContractMethod<[
accounts: AddressLike[],
ids: BigNumberish[]
], [
bigint[]
], "view">;
canExtendSubnames: TypedContractMethod<[
node: BytesLike,
addr: AddressLike
], [
boolean
], "view">;
canModifyName: TypedContractMethod<[
node: BytesLike,
addr: AddressLike
], [
boolean
], "view">;
controllers: TypedContractMethod<[arg0: AddressLike], [boolean], "view">;
ens: TypedContractMethod<[], [string], "view">;
extendExpiry: TypedContractMethod<[
parentNode: BytesLike,
labelhash: BytesLike,
expiry: BigNumberish
], [
bigint
], "nonpayable">;
getApproved: TypedContractMethod<[id: BigNumberish], [string], "view">;
getData: TypedContractMethod<[
id: BigNumberish
], [
[
string,
bigint,
bigint
] & {
owner: string;
fuses: bigint;
expiry: bigint;
}
], "view">;
isApprovedForAll: TypedContractMethod<[
account: AddressLike,
operator: AddressLike
], [
boolean
], "view">;
"isWrapped(bytes32,bytes32)": TypedContractMethod<[
parentNode: BytesLike,
labelhash: BytesLike
], [
boolean
], "view">;
"isWrapped(bytes32)": TypedContractMethod<[
node: BytesLike
], [
boolean
], "view">;
metadataService: TypedContractMethod<[], [string], "view">;
name: TypedContractMethod<[], [string], "view">;
names: TypedContractMethod<[arg0: BytesLike], [string], "view">;
onERC721Received: TypedContractMethod<[
to: AddressLike,
arg1: AddressLike,
tokenId: BigNumberish,
data: BytesLike
], [
string
], "nonpayable">;
owner: TypedContractMethod<[], [string], "view">;
ownerOf: TypedContractMethod<[id: BigNumberish], [string], "view">;
recoverFunds: TypedContractMethod<[
_token: AddressLike,
_to: AddressLike,
_amount: BigNumberish
], [
void
], "nonpayable">;
registerAndWrapETH2LD: TypedContractMethod<[
label: string,
wrappedOwner: AddressLike,
duration: BigNumberish,
resolver: AddressLike,
ownerControlledFuses: BigNumberish
], [
bigint
], "nonpayable">;
registrar: TypedContractMethod<[], [string], "view">;
renew: TypedContractMethod<[
tokenId: BigNumberish,
duration: BigNumberish
], [
bigint
], "nonpayable">;
renounceOwnership: TypedContractMethod<[], [void], "nonpayable">;
safeBatchTransferFrom: TypedContractMethod<[
from: AddressLike,
to: AddressLike,
ids: BigNumberish[],
amounts: BigNumberish[],
data: BytesLike
], [
void
], "nonpayable">;
safeTransferFrom: TypedContractMethod<[
from: AddressLike,
to: AddressLike,
id: BigNumberish,
amount: BigNumberish,
data: BytesLike
], [
void
], "nonpayable">;
setApprovalForAll: TypedContractMethod<[
operator: AddressLike,
approved: boolean
], [
void
], "nonpayable">;
setChildFuses: TypedContractMethod<[
parentNode: BytesLike,
labelhash: BytesLike,
fuses: BigNumberish,
expiry: BigNumberish
], [
void
], "nonpayable">;
setController: TypedContractMethod<[
controller: AddressLike,
active: boolean
], [
void
], "nonpayable">;
setFuses: TypedContractMethod<[
node: BytesLike,
ownerControlledFuses: BigNumberish
], [
bigint
], "nonpayable">;
setMetadataService: TypedContractMethod<[
_metadataService: AddressLike
], [
void
], "nonpayable">;
setRecord: TypedContractMethod<[
node: BytesLike,
owner: AddressLike,
resolver: AddressLike,
ttl: BigNumberish
], [
void
], "nonpayable">;
setResolver: TypedContractMethod<[
node: BytesLike,
resolver: AddressLike
], [
void
], "nonpayable">;
setSubnodeOwner: TypedContractMethod<[
parentNode: BytesLike,
label: string,
owner: AddressLike,
fuses: BigNumberish,
expiry: BigNumberish
], [
string
], "nonpayable">;
setSubnodeRecord: TypedContractMethod<[
parentNode: BytesLike,
label: string,
owner: AddressLike,
resolver: AddressLike,
ttl: BigNumberish,
fuses: BigNumberish,
expiry: BigNumberish
], [
string
], "nonpayable">;
setTTL: TypedContractMethod<[
node: BytesLike,
ttl: BigNumberish
], [
void
], "nonpayable">;
setUpgradeContract: TypedContractMethod<[
_upgradeAddress: AddressLike
], [
void
], "nonpayable">;
supportsInterface: TypedContractMethod<[
interfaceId: BytesLike
], [
boolean
], "view">;
transferOwnership: TypedContractMethod<[
newOwner: AddressLike
], [
void
], "nonpayable">;
unwrap: TypedContractMethod<[
parentNode: BytesLike,
labelhash: BytesLike,
controller: AddressLike
], [
void
], "nonpayable">;
unwrapETH2LD: TypedContractMethod<[
labelhash: BytesLike,
registrant: AddressLike,
controller: AddressLike
], [
void
], "nonpayable">;
upgrade: TypedContractMethod<[
name: BytesLike,
extraData: BytesLike
], [
void
], "nonpayable">;
upgradeContract: TypedContractMethod<[], [string], "view">;
uri: TypedContractMethod<[tokenId: BigNumberish], [string], "view">;
wrap: TypedContractMethod<[
name: BytesLike,
wrappedOwner: AddressLike,
resolver: AddressLike
], [
void
], "nonpayable">;
wrapETH2LD: TypedContractMethod<[
label: string,
wrappedOwner: AddressLike,
ownerControlledFuses: BigNumberish,
resolver: AddressLike
], [
bigint
], "nonpayable">;
getFunction<T extends ContractMethod = ContractMethod>(key: string | FunctionFragment): T;
getFunction(nameOrSignature: "_tokens"): TypedContractMethod<[arg0: BigNumberish], [bigint], "view">;
getFunction(nameOrSignature: "allFusesBurned"): TypedContractMethod<[
node: BytesLike,
fuseMask: BigNumberish
], [
boolean
], "view">;
getFunction(nameOrSignature: "approve"): TypedContractMethod<[
to: AddressLike,
tokenId: BigNumberish
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "balanceOf"): TypedContractMethod<[
account: AddressLike,
id: BigNumberish
], [
bigint
], "view">;
getFunction(nameOrSignature: "balanceOfBatch"): TypedContractMethod<[
accounts: AddressLike[],
ids: BigNumberish[]
], [
bigint[]
], "view">;
getFunction(nameOrSignature: "canExtendSubnames"): TypedContractMethod<[
node: BytesLike,
addr: AddressLike
], [
boolean
], "view">;
getFunction(nameOrSignature: "canModifyName"): TypedContractMethod<[
node: BytesLike,
addr: AddressLike
], [
boolean
], "view">;
getFunction(nameOrSignature: "controllers"): TypedContractMethod<[arg0: AddressLike], [boolean], "view">;
getFunction(nameOrSignature: "ens"): TypedContractMethod<[], [string], "view">;
getFunction(nameOrSignature: "extendExpiry"): TypedContractMethod<[
parentNode: BytesLike,
labelhash: BytesLike,
expiry: BigNumberish
], [
bigint
], "nonpayable">;
getFunction(nameOrSignature: "getApproved"): TypedContractMethod<[id: BigNumberish], [string], "view">;
getFunction(nameOrSignature: "getData"): TypedContractMethod<[
id: BigNumberish
], [
[
string,
bigint,
bigint
] & {
owner: string;
fuses: bigint;
expiry: bigint;
}
], "view">;
getFunction(nameOrSignature: "isApprovedForAll"): TypedContractMethod<[
account: AddressLike,
operator: AddressLike
], [
boolean
], "view">;
getFunction(nameOrSignature: "isWrapped(bytes32,bytes32)"): TypedContractMethod<[
parentNode: BytesLike,
labelhash: BytesLike
], [
boolean
], "view">;
getFunction(nameOrSignature: "isWrapped(bytes32)"): TypedContractMethod<[node: BytesLike], [boolean], "view">;
getFunction(nameOrSignature: "metadataService"): TypedContractMethod<[], [string], "view">;
getFunction(nameOrSignature: "name"): TypedContractMethod<[], [string], "view">;
getFunction(nameOrSignature: "names"): TypedContractMethod<[arg0: BytesLike], [string], "view">;
getFunction(nameOrSignature: "onERC721Received"): TypedContractMethod<[
to: AddressLike,
arg1: AddressLike,
tokenId: BigNumberish,
data: BytesLike
], [
string
], "nonpayable">;
getFunction(nameOrSignature: "owner"): TypedContractMethod<[], [string], "view">;
getFunction(nameOrSignature: "ownerOf"): TypedContractMethod<[id: BigNumberish], [string], "view">;
getFunction(nameOrSignature: "recoverFunds"): TypedContractMethod<[
_token: AddressLike,
_to: AddressLike,
_amount: BigNumberish
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "registerAndWrapETH2LD"): TypedContractMethod<[
label: string,
wrappedOwner: AddressLike,
duration: BigNumberish,
resolver: AddressLike,
ownerControlledFuses: BigNumberish
], [
bigint
], "nonpayable">;
getFunction(nameOrSignature: "registrar"): TypedContractMethod<[], [string], "view">;
getFunction(nameOrSignature: "renew"): TypedContractMethod<[
tokenId: BigNumberish,
duration: BigNumberish
], [
bigint
], "nonpayable">;
getFunction(nameOrSignature: "renounceOwnership"): TypedContractMethod<[], [void], "nonpayable">;
getFunction(nameOrSignature: "safeBatchTransferFrom"): TypedContractMethod<[
from: AddressLike,
to: AddressLike,
ids: BigNumberish[],
amounts: BigNumberish[],
data: BytesLike
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "safeTransferFrom"): TypedContractMethod<[
from: AddressLike,
to: AddressLike,
id: BigNumberish,
amount: BigNumberish,
data: BytesLike
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "setApprovalForAll"): TypedContractMethod<[
operator: AddressLike,
approved: boolean
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "setChildFuses"): TypedContractMethod<[
parentNode: BytesLike,
labelhash: BytesLike,
fuses: BigNumberish,
expiry: BigNumberish
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "setController"): TypedContractMethod<[
controller: AddressLike,
active: boolean
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "setFuses"): TypedContractMethod<[
node: BytesLike,
ownerControlledFuses: BigNumberish
], [
bigint
], "nonpayable">;
getFunction(nameOrSignature: "setMetadataService"): TypedContractMethod<[_metadataService: AddressLike], [void], "nonpayable">;
getFunction(nameOrSignature: "setRecord"): TypedContractMethod<[
node: BytesLike,
owner: AddressLike,
resolver: AddressLike,
ttl: BigNumberish
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "setResolver"): TypedContractMethod<[
node: BytesLike,
resolver: AddressLike
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "setSubnodeOwner"): TypedContractMethod<[
parentNode: BytesLike,
label: string,
owner: AddressLike,
fuses: BigNumberish,
expiry: BigNumberish
], [
string
], "nonpayable">;
getFunction(nameOrSignature: "setSubnodeRecord"): TypedContractMethod<[
parentNode: BytesLike,
label: string,
owner: AddressLike,
resolver: AddressLike,
ttl: BigNumberish,
fuses: BigNumberish,
expiry: BigNumberish
], [
string
], "nonpayable">;
getFunction(nameOrSignature: "setTTL"): TypedContractMethod<[
node: BytesLike,
ttl: BigNumberish
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "setUpgradeContract"): TypedContractMethod<[_upgradeAddress: AddressLike], [void], "nonpayable">;
getFunction(nameOrSignature: "supportsInterface"): TypedContractMethod<[interfaceId: BytesLike], [boolean], "view">;
getFunction(nameOrSignature: "transferOwnership"): TypedContractMethod<[newOwner: AddressLike], [void], "nonpayable">;
getFunction(nameOrSignature: "unwrap"): TypedContractMethod<[
parentNode: BytesLike,
labelhash: BytesLike,
controller: AddressLike
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "unwrapETH2LD"): TypedContractMethod<[
labelhash: BytesLike,
registrant: AddressLike,
controller: AddressLike
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "upgrade"): TypedContractMethod<[
name: BytesLike,
extraData: BytesLike
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "upgradeContract"): TypedContractMethod<[], [string], "view">;
getFunction(nameOrSignature: "uri"): TypedContractMethod<[tokenId: BigNumberish], [string], "view">;
getFunction(nameOrSignature: "wrap"): TypedContractMethod<[
name: BytesLike,
wrappedOwner: AddressLike,
resolver: AddressLike
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "wrapETH2LD"): TypedContractMethod<[
label: string,
wrappedOwner: AddressLike,
ownerControlledFuses: BigNumberish,
resolver: AddressLike
], [
bigint
], "nonpayable">;
getEvent(key: "Approval"): TypedContractEvent<ApprovalEvent.InputTuple, ApprovalEvent.OutputTuple, ApprovalEvent.OutputObject>;
getEvent(key: "ApprovalForAll"): TypedContractEvent<ApprovalForAllEvent.InputTuple, ApprovalForAllEvent.OutputTuple, ApprovalForAllEvent.OutputObject>;
getEvent(key: "ControllerChanged"): TypedContractEvent<ControllerChangedEvent.InputTuple, ControllerChangedEvent.OutputTuple, ControllerChangedEvent.OutputObject>;
getEvent(key: "ExpiryExtended"): TypedContractEvent<ExpiryExtendedEvent.InputTuple, ExpiryExtendedEvent.OutputTuple, ExpiryExtendedEvent.OutputObject>;
getEvent(key: "FusesSet"): TypedContractEvent<FusesSetEvent.InputTuple, FusesSetEvent.OutputTuple, FusesSetEvent.OutputObject>;
getEvent(key: "NameUnwrapped"): TypedContractEvent<NameUnwrappedEvent.InputTuple, NameUnwrappedEvent.OutputTuple, NameUnwrappedEvent.OutputObject>;
getEvent(key: "NameWrapped"): TypedContractEvent<NameWrappedEvent.InputTuple, NameWrappedEvent.OutputTuple, NameWrappedEvent.OutputObject>;
getEvent(key: "OwnershipTransferred"): TypedContractEvent<OwnershipTransferredEvent.InputTuple, OwnershipTransferredEvent.OutputTuple, OwnershipTransferredEvent.OutputObject>;
getEvent(key: "TransferBatch"): TypedContractEvent<TransferBatchEvent.InputTuple, TransferBatchEvent.OutputTuple, TransferBatchEvent.OutputObject>;
getEvent(key: "TransferSingle"): TypedContractEvent<TransferSingleEvent.InputTuple, TransferSingleEvent.OutputTuple, TransferSingleEvent.OutputObject>;
getEvent(key: "URI"): TypedContractEvent<URIEvent.InputTuple, URIEvent.OutputTuple, URIEvent.OutputObject>;
filters: {
"Approval(address,address,uint256)": TypedContractEvent<ApprovalEvent.InputTuple, ApprovalEvent.OutputTuple, ApprovalEvent.OutputObject>;
Approval: TypedContractEvent<ApprovalEvent.InputTuple, ApprovalEvent.OutputTuple, ApprovalEvent.OutputObject>;
"ApprovalForAll(address,address,bool)": TypedContractEvent<ApprovalForAllEvent.InputTuple, ApprovalForAllEvent.OutputTuple, ApprovalForAllEvent.OutputObject>;
ApprovalForAll: TypedContractEvent<ApprovalForAllEvent.InputTuple, ApprovalForAllEvent.OutputTuple, ApprovalForAllEvent.OutputObject>;
"ControllerChanged(address,bool)": TypedContractEvent<ControllerChangedEvent.InputTuple, ControllerChangedEvent.OutputTuple, ControllerChangedEvent.OutputObject>;
ControllerChanged: TypedContractEvent<ControllerChangedEvent.InputTuple, ControllerChangedEvent.OutputTuple, ControllerChangedEvent.OutputObject>;
"ExpiryExtended(bytes32,uint64)": TypedContractEvent<ExpiryExtendedEvent.InputTuple, ExpiryExtendedEvent.OutputTuple, ExpiryExtendedEvent.OutputObject>;
ExpiryExtended: TypedContractEvent<ExpiryExtendedEvent.InputTuple, ExpiryExtendedEvent.OutputTuple, ExpiryExtendedEvent.OutputObject>;
"FusesSet(bytes32,uint32)": TypedContractEvent<FusesSetEvent.InputTuple, FusesSetEvent.OutputTuple, FusesSetEvent.OutputObject>;
FusesSet: TypedContractEvent<FusesSetEvent.InputTuple, FusesSetEvent.OutputTuple, FusesSetEvent.OutputObject>;
"NameUnwrapped(bytes32,address)": TypedContractEvent<NameUnwrappedEvent.InputTuple, NameUnwrappedEvent.OutputTuple, NameUnwrappedEvent.OutputObject>;
NameUnwrapped: TypedContractEvent<NameUnwrappedEvent.InputTuple, NameUnwrappedEvent.OutputTuple, NameUnwrappedEvent.OutputObject>;
"NameWrapped(bytes32,bytes,address,uint32,uint64)": TypedContractEvent<NameWrappedEvent.InputTuple, NameWrappedEvent.OutputTuple, NameWrappedEvent.OutputObject>;
NameWrapped: TypedContractEvent<NameWrappedEvent.InputTuple, NameWrappedEvent.OutputTuple, NameWrappedEvent.OutputObject>;
"OwnershipTransferred(address,address)": TypedContractEvent<OwnershipTransferredEvent.InputTuple, OwnershipTransferredEvent.OutputTuple, OwnershipTransferredEvent.OutputObject>;
OwnershipTransferred: TypedContractEvent<OwnershipTransferredEvent.InputTuple, OwnershipTransferredEvent.OutputTuple, OwnershipTransferredEvent.OutputObject>;
"TransferBatch(address,address,address,uint256[],uint256[])": TypedContractEvent<TransferBatchEvent.InputTuple, TransferBatchEvent.OutputTuple, TransferBatchEvent.OutputObject>;
TransferBatch: TypedContractEvent<TransferBatchEvent.InputTuple, TransferBatchEvent.OutputTuple, TransferBatchEvent.OutputObject>;
"TransferSingle(address,address,address,uint256,uint256)": TypedContractEvent<TransferSingleEvent.InputTuple, TransferSingleEvent.OutputTuple, TransferSingleEvent.OutputObject>;
TransferSingle: TypedContractEvent<TransferSingleEvent.InputTuple, TransferSingleEvent.OutputTuple, TransferSingleEvent.OutputObject>;
"URI(string,uint256)": TypedContractEvent<URIEvent.InputTuple, URIEvent.OutputTuple, URIEvent.OutputObject>;
URI: TypedContractEvent<URIEvent.InputTuple, URIEvent.OutputTuple, URIEvent.OutputObject>;
};
}

256
dist/typechain/ENSRegistry.d.ts vendored Normal file
View File

@@ -0,0 +1,256 @@
import type { BaseContract, BigNumberish, BytesLike, FunctionFragment, Result, Interface, EventFragment, AddressLike, ContractRunner, ContractMethod, Listener } from "ethers";
import type { TypedContractEvent, TypedDeferredTopicFilter, TypedEventLog, TypedLogDescription, TypedListener, TypedContractMethod } from "./common";
export interface ENSRegistryInterface extends Interface {
getFunction(nameOrSignature: "isApprovedForAll" | "old" | "owner" | "recordExists" | "resolver" | "setApprovalForAll" | "setOwner" | "setRecord" | "setResolver" | "setSubnodeOwner" | "setSubnodeRecord" | "setTTL" | "ttl"): FunctionFragment;
getEvent(nameOrSignatureOrTopic: "ApprovalForAll" | "NewOwner" | "NewResolver" | "NewTTL" | "Transfer"): EventFragment;
encodeFunctionData(functionFragment: "isApprovedForAll", values: [AddressLike, AddressLike]): string;
encodeFunctionData(functionFragment: "old", values?: undefined): string;
encodeFunctionData(functionFragment: "owner", values: [BytesLike]): string;
encodeFunctionData(functionFragment: "recordExists", values: [BytesLike]): string;
encodeFunctionData(functionFragment: "resolver", values: [BytesLike]): string;
encodeFunctionData(functionFragment: "setApprovalForAll", values: [AddressLike, boolean]): string;
encodeFunctionData(functionFragment: "setOwner", values: [BytesLike, AddressLike]): string;
encodeFunctionData(functionFragment: "setRecord", values: [BytesLike, AddressLike, AddressLike, BigNumberish]): string;
encodeFunctionData(functionFragment: "setResolver", values: [BytesLike, AddressLike]): string;
encodeFunctionData(functionFragment: "setSubnodeOwner", values: [BytesLike, BytesLike, AddressLike]): string;
encodeFunctionData(functionFragment: "setSubnodeRecord", values: [BytesLike, BytesLike, AddressLike, AddressLike, BigNumberish]): string;
encodeFunctionData(functionFragment: "setTTL", values: [BytesLike, BigNumberish]): string;
encodeFunctionData(functionFragment: "ttl", values: [BytesLike]): string;
decodeFunctionResult(functionFragment: "isApprovedForAll", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "old", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "owner", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "recordExists", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "resolver", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setApprovalForAll", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setOwner", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setRecord", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setResolver", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setSubnodeOwner", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setSubnodeRecord", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setTTL", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "ttl", data: BytesLike): Result;
}
export declare namespace ApprovalForAllEvent {
type InputTuple = [
owner: AddressLike,
operator: AddressLike,
approved: boolean
];
type OutputTuple = [
owner: string,
operator: string,
approved: boolean
];
interface OutputObject {
owner: string;
operator: string;
approved: boolean;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace NewOwnerEvent {
type InputTuple = [
node: BytesLike,
label: BytesLike,
owner: AddressLike
];
type OutputTuple = [node: string, label: string, owner: string];
interface OutputObject {
node: string;
label: string;
owner: string;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace NewResolverEvent {
type InputTuple = [node: BytesLike, resolver: AddressLike];
type OutputTuple = [node: string, resolver: string];
interface OutputObject {
node: string;
resolver: string;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace NewTTLEvent {
type InputTuple = [node: BytesLike, ttl: BigNumberish];
type OutputTuple = [node: string, ttl: bigint];
interface OutputObject {
node: string;
ttl: bigint;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace TransferEvent {
type InputTuple = [node: BytesLike, owner: AddressLike];
type OutputTuple = [node: string, owner: string];
interface OutputObject {
node: string;
owner: string;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export interface ENSRegistry extends BaseContract {
connect(runner?: ContractRunner | null): ENSRegistry;
waitForDeployment(): Promise<this>;
interface: ENSRegistryInterface;
queryFilter<TCEvent extends TypedContractEvent>(event: TCEvent, fromBlockOrBlockhash?: string | number | undefined, toBlock?: string | number | undefined): Promise<Array<TypedEventLog<TCEvent>>>;
queryFilter<TCEvent extends TypedContractEvent>(filter: TypedDeferredTopicFilter<TCEvent>, fromBlockOrBlockhash?: string | number | undefined, toBlock?: string | number | undefined): Promise<Array<TypedEventLog<TCEvent>>>;
on<TCEvent extends TypedContractEvent>(event: TCEvent, listener: TypedListener<TCEvent>): Promise<this>;
on<TCEvent extends TypedContractEvent>(filter: TypedDeferredTopicFilter<TCEvent>, listener: TypedListener<TCEvent>): Promise<this>;
once<TCEvent extends TypedContractEvent>(event: TCEvent, listener: TypedListener<TCEvent>): Promise<this>;
once<TCEvent extends TypedContractEvent>(filter: TypedDeferredTopicFilter<TCEvent>, listener: TypedListener<TCEvent>): Promise<this>;
listeners<TCEvent extends TypedContractEvent>(event: TCEvent): Promise<Array<TypedListener<TCEvent>>>;
listeners(eventName?: string): Promise<Array<Listener>>;
removeAllListeners<TCEvent extends TypedContractEvent>(event?: TCEvent): Promise<this>;
isApprovedForAll: TypedContractMethod<[
owner: AddressLike,
operator: AddressLike
], [
boolean
], "view">;
old: TypedContractMethod<[], [string], "view">;
owner: TypedContractMethod<[node: BytesLike], [string], "view">;
recordExists: TypedContractMethod<[node: BytesLike], [boolean], "view">;
resolver: TypedContractMethod<[node: BytesLike], [string], "view">;
setApprovalForAll: TypedContractMethod<[
operator: AddressLike,
approved: boolean
], [
void
], "nonpayable">;
setOwner: TypedContractMethod<[
node: BytesLike,
owner: AddressLike
], [
void
], "nonpayable">;
setRecord: TypedContractMethod<[
node: BytesLike,
owner: AddressLike,
resolver: AddressLike,
ttl: BigNumberish
], [
void
], "nonpayable">;
setResolver: TypedContractMethod<[
node: BytesLike,
resolver: AddressLike
], [
void
], "nonpayable">;
setSubnodeOwner: TypedContractMethod<[
node: BytesLike,
label: BytesLike,
owner: AddressLike
], [
string
], "nonpayable">;
setSubnodeRecord: TypedContractMethod<[
node: BytesLike,
label: BytesLike,
owner: AddressLike,
resolver: AddressLike,
ttl: BigNumberish
], [
void
], "nonpayable">;
setTTL: TypedContractMethod<[
node: BytesLike,
ttl: BigNumberish
], [
void
], "nonpayable">;
ttl: TypedContractMethod<[node: BytesLike], [bigint], "view">;
getFunction<T extends ContractMethod = ContractMethod>(key: string | FunctionFragment): T;
getFunction(nameOrSignature: "isApprovedForAll"): TypedContractMethod<[
owner: AddressLike,
operator: AddressLike
], [
boolean
], "view">;
getFunction(nameOrSignature: "old"): TypedContractMethod<[], [string], "view">;
getFunction(nameOrSignature: "owner"): TypedContractMethod<[node: BytesLike], [string], "view">;
getFunction(nameOrSignature: "recordExists"): TypedContractMethod<[node: BytesLike], [boolean], "view">;
getFunction(nameOrSignature: "resolver"): TypedContractMethod<[node: BytesLike], [string], "view">;
getFunction(nameOrSignature: "setApprovalForAll"): TypedContractMethod<[
operator: AddressLike,
approved: boolean
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "setOwner"): TypedContractMethod<[
node: BytesLike,
owner: AddressLike
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "setRecord"): TypedContractMethod<[
node: BytesLike,
owner: AddressLike,
resolver: AddressLike,
ttl: BigNumberish
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "setResolver"): TypedContractMethod<[
node: BytesLike,
resolver: AddressLike
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "setSubnodeOwner"): TypedContractMethod<[
node: BytesLike,
label: BytesLike,
owner: AddressLike
], [
string
], "nonpayable">;
getFunction(nameOrSignature: "setSubnodeRecord"): TypedContractMethod<[
node: BytesLike,
label: BytesLike,
owner: AddressLike,
resolver: AddressLike,
ttl: BigNumberish
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "setTTL"): TypedContractMethod<[
node: BytesLike,
ttl: BigNumberish
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "ttl"): TypedContractMethod<[node: BytesLike], [bigint], "view">;
getEvent(key: "ApprovalForAll"): TypedContractEvent<ApprovalForAllEvent.InputTuple, ApprovalForAllEvent.OutputTuple, ApprovalForAllEvent.OutputObject>;
getEvent(key: "NewOwner"): TypedContractEvent<NewOwnerEvent.InputTuple, NewOwnerEvent.OutputTuple, NewOwnerEvent.OutputObject>;
getEvent(key: "NewResolver"): TypedContractEvent<NewResolverEvent.InputTuple, NewResolverEvent.OutputTuple, NewResolverEvent.OutputObject>;
getEvent(key: "NewTTL"): TypedContractEvent<NewTTLEvent.InputTuple, NewTTLEvent.OutputTuple, NewTTLEvent.OutputObject>;
getEvent(key: "Transfer"): TypedContractEvent<TransferEvent.InputTuple, TransferEvent.OutputTuple, TransferEvent.OutputObject>;
filters: {
"ApprovalForAll(address,address,bool)": TypedContractEvent<ApprovalForAllEvent.InputTuple, ApprovalForAllEvent.OutputTuple, ApprovalForAllEvent.OutputObject>;
ApprovalForAll: TypedContractEvent<ApprovalForAllEvent.InputTuple, ApprovalForAllEvent.OutputTuple, ApprovalForAllEvent.OutputObject>;
"NewOwner(bytes32,bytes32,address)": TypedContractEvent<NewOwnerEvent.InputTuple, NewOwnerEvent.OutputTuple, NewOwnerEvent.OutputObject>;
NewOwner: TypedContractEvent<NewOwnerEvent.InputTuple, NewOwnerEvent.OutputTuple, NewOwnerEvent.OutputObject>;
"NewResolver(bytes32,address)": TypedContractEvent<NewResolverEvent.InputTuple, NewResolverEvent.OutputTuple, NewResolverEvent.OutputObject>;
NewResolver: TypedContractEvent<NewResolverEvent.InputTuple, NewResolverEvent.OutputTuple, NewResolverEvent.OutputObject>;
"NewTTL(bytes32,uint64)": TypedContractEvent<NewTTLEvent.InputTuple, NewTTLEvent.OutputTuple, NewTTLEvent.OutputObject>;
NewTTL: TypedContractEvent<NewTTLEvent.InputTuple, NewTTLEvent.OutputTuple, NewTTLEvent.OutputObject>;
"Transfer(bytes32,address)": TypedContractEvent<TransferEvent.InputTuple, TransferEvent.OutputTuple, TransferEvent.OutputObject>;
Transfer: TypedContractEvent<TransferEvent.InputTuple, TransferEvent.OutputTuple, TransferEvent.OutputObject>;
};
}

660
dist/typechain/ENSResolver.d.ts vendored Normal file
View File

@@ -0,0 +1,660 @@
import type { BaseContract, BigNumberish, BytesLike, FunctionFragment, Result, Interface, EventFragment, AddressLike, ContractRunner, ContractMethod, Listener } from "ethers";
import type { TypedContractEvent, TypedDeferredTopicFilter, TypedEventLog, TypedLogDescription, TypedListener, TypedContractMethod } from "./common";
export interface ENSResolverInterface extends Interface {
getFunction(nameOrSignature: "ABI" | "addr(bytes32)" | "addr(bytes32,uint256)" | "approve" | "clearRecords" | "contenthash" | "dnsRecord" | "hasDNSRecords" | "interfaceImplementer" | "isApprovedFor" | "isApprovedForAll" | "multicall" | "multicallWithNodeCheck" | "name" | "pubkey" | "recordVersions" | "setABI" | "setAddr(bytes32,uint256,bytes)" | "setAddr(bytes32,address)" | "setApprovalForAll" | "setContenthash" | "setDNSRecords" | "setInterface" | "setName" | "setPubkey" | "setText" | "setZonehash" | "supportsInterface" | "text" | "zonehash"): FunctionFragment;
getEvent(nameOrSignatureOrTopic: "ABIChanged" | "AddrChanged" | "AddressChanged" | "ApprovalForAll" | "Approved" | "ContenthashChanged" | "DNSRecordChanged" | "DNSRecordDeleted" | "DNSZonehashChanged" | "InterfaceChanged" | "NameChanged" | "PubkeyChanged" | "TextChanged" | "VersionChanged"): EventFragment;
encodeFunctionData(functionFragment: "ABI", values: [BytesLike, BigNumberish]): string;
encodeFunctionData(functionFragment: "addr(bytes32)", values: [BytesLike]): string;
encodeFunctionData(functionFragment: "addr(bytes32,uint256)", values: [BytesLike, BigNumberish]): string;
encodeFunctionData(functionFragment: "approve", values: [BytesLike, AddressLike, boolean]): string;
encodeFunctionData(functionFragment: "clearRecords", values: [BytesLike]): string;
encodeFunctionData(functionFragment: "contenthash", values: [BytesLike]): string;
encodeFunctionData(functionFragment: "dnsRecord", values: [BytesLike, BytesLike, BigNumberish]): string;
encodeFunctionData(functionFragment: "hasDNSRecords", values: [BytesLike, BytesLike]): string;
encodeFunctionData(functionFragment: "interfaceImplementer", values: [BytesLike, BytesLike]): string;
encodeFunctionData(functionFragment: "isApprovedFor", values: [AddressLike, BytesLike, AddressLike]): string;
encodeFunctionData(functionFragment: "isApprovedForAll", values: [AddressLike, AddressLike]): string;
encodeFunctionData(functionFragment: "multicall", values: [BytesLike[]]): string;
encodeFunctionData(functionFragment: "multicallWithNodeCheck", values: [BytesLike, BytesLike[]]): string;
encodeFunctionData(functionFragment: "name", values: [BytesLike]): string;
encodeFunctionData(functionFragment: "pubkey", values: [BytesLike]): string;
encodeFunctionData(functionFragment: "recordVersions", values: [BytesLike]): string;
encodeFunctionData(functionFragment: "setABI", values: [BytesLike, BigNumberish, BytesLike]): string;
encodeFunctionData(functionFragment: "setAddr(bytes32,uint256,bytes)", values: [BytesLike, BigNumberish, BytesLike]): string;
encodeFunctionData(functionFragment: "setAddr(bytes32,address)", values: [BytesLike, AddressLike]): string;
encodeFunctionData(functionFragment: "setApprovalForAll", values: [AddressLike, boolean]): string;
encodeFunctionData(functionFragment: "setContenthash", values: [BytesLike, BytesLike]): string;
encodeFunctionData(functionFragment: "setDNSRecords", values: [BytesLike, BytesLike]): string;
encodeFunctionData(functionFragment: "setInterface", values: [BytesLike, BytesLike, AddressLike]): string;
encodeFunctionData(functionFragment: "setName", values: [BytesLike, string]): string;
encodeFunctionData(functionFragment: "setPubkey", values: [BytesLike, BytesLike, BytesLike]): string;
encodeFunctionData(functionFragment: "setText", values: [BytesLike, string, string]): string;
encodeFunctionData(functionFragment: "setZonehash", values: [BytesLike, BytesLike]): string;
encodeFunctionData(functionFragment: "supportsInterface", values: [BytesLike]): string;
encodeFunctionData(functionFragment: "text", values: [BytesLike, string]): string;
encodeFunctionData(functionFragment: "zonehash", values: [BytesLike]): string;
decodeFunctionResult(functionFragment: "ABI", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "addr(bytes32)", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "addr(bytes32,uint256)", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "approve", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "clearRecords", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "contenthash", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "dnsRecord", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "hasDNSRecords", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "interfaceImplementer", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "isApprovedFor", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "isApprovedForAll", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "multicall", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "multicallWithNodeCheck", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "name", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "pubkey", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "recordVersions", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setABI", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setAddr(bytes32,uint256,bytes)", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setAddr(bytes32,address)", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setApprovalForAll", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setContenthash", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setDNSRecords", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setInterface", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setName", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setPubkey", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setText", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setZonehash", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "supportsInterface", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "text", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "zonehash", data: BytesLike): Result;
}
export declare namespace ABIChangedEvent {
type InputTuple = [node: BytesLike, contentType: BigNumberish];
type OutputTuple = [node: string, contentType: bigint];
interface OutputObject {
node: string;
contentType: bigint;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace AddrChangedEvent {
type InputTuple = [node: BytesLike, a: AddressLike];
type OutputTuple = [node: string, a: string];
interface OutputObject {
node: string;
a: string;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace AddressChangedEvent {
type InputTuple = [
node: BytesLike,
coinType: BigNumberish,
newAddress: BytesLike
];
type OutputTuple = [
node: string,
coinType: bigint,
newAddress: string
];
interface OutputObject {
node: string;
coinType: bigint;
newAddress: string;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace ApprovalForAllEvent {
type InputTuple = [
owner: AddressLike,
operator: AddressLike,
approved: boolean
];
type OutputTuple = [
owner: string,
operator: string,
approved: boolean
];
interface OutputObject {
owner: string;
operator: string;
approved: boolean;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace ApprovedEvent {
type InputTuple = [
owner: AddressLike,
node: BytesLike,
delegate: AddressLike,
approved: boolean
];
type OutputTuple = [
owner: string,
node: string,
delegate: string,
approved: boolean
];
interface OutputObject {
owner: string;
node: string;
delegate: string;
approved: boolean;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace ContenthashChangedEvent {
type InputTuple = [node: BytesLike, hash: BytesLike];
type OutputTuple = [node: string, hash: string];
interface OutputObject {
node: string;
hash: string;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace DNSRecordChangedEvent {
type InputTuple = [
node: BytesLike,
name: BytesLike,
resource: BigNumberish,
record: BytesLike
];
type OutputTuple = [
node: string,
name: string,
resource: bigint,
record: string
];
interface OutputObject {
node: string;
name: string;
resource: bigint;
record: string;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace DNSRecordDeletedEvent {
type InputTuple = [
node: BytesLike,
name: BytesLike,
resource: BigNumberish
];
type OutputTuple = [node: string, name: string, resource: bigint];
interface OutputObject {
node: string;
name: string;
resource: bigint;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace DNSZonehashChangedEvent {
type InputTuple = [
node: BytesLike,
lastzonehash: BytesLike,
zonehash: BytesLike
];
type OutputTuple = [
node: string,
lastzonehash: string,
zonehash: string
];
interface OutputObject {
node: string;
lastzonehash: string;
zonehash: string;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace InterfaceChangedEvent {
type InputTuple = [
node: BytesLike,
interfaceID: BytesLike,
implementer: AddressLike
];
type OutputTuple = [
node: string,
interfaceID: string,
implementer: string
];
interface OutputObject {
node: string;
interfaceID: string;
implementer: string;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace NameChangedEvent {
type InputTuple = [node: BytesLike, name: string];
type OutputTuple = [node: string, name: string];
interface OutputObject {
node: string;
name: string;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace PubkeyChangedEvent {
type InputTuple = [node: BytesLike, x: BytesLike, y: BytesLike];
type OutputTuple = [node: string, x: string, y: string];
interface OutputObject {
node: string;
x: string;
y: string;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace TextChangedEvent {
type InputTuple = [
node: BytesLike,
indexedKey: string,
key: string,
value: string
];
type OutputTuple = [
node: string,
indexedKey: string,
key: string,
value: string
];
interface OutputObject {
node: string;
indexedKey: string;
key: string;
value: string;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export declare namespace VersionChangedEvent {
type InputTuple = [node: BytesLike, newVersion: BigNumberish];
type OutputTuple = [node: string, newVersion: bigint];
interface OutputObject {
node: string;
newVersion: bigint;
}
type Event = TypedContractEvent<InputTuple, OutputTuple, OutputObject>;
type Filter = TypedDeferredTopicFilter<Event>;
type Log = TypedEventLog<Event>;
type LogDescription = TypedLogDescription<Event>;
}
export interface ENSResolver extends BaseContract {
connect(runner?: ContractRunner | null): ENSResolver;
waitForDeployment(): Promise<this>;
interface: ENSResolverInterface;
queryFilter<TCEvent extends TypedContractEvent>(event: TCEvent, fromBlockOrBlockhash?: string | number | undefined, toBlock?: string | number | undefined): Promise<Array<TypedEventLog<TCEvent>>>;
queryFilter<TCEvent extends TypedContractEvent>(filter: TypedDeferredTopicFilter<TCEvent>, fromBlockOrBlockhash?: string | number | undefined, toBlock?: string | number | undefined): Promise<Array<TypedEventLog<TCEvent>>>;
on<TCEvent extends TypedContractEvent>(event: TCEvent, listener: TypedListener<TCEvent>): Promise<this>;
on<TCEvent extends TypedContractEvent>(filter: TypedDeferredTopicFilter<TCEvent>, listener: TypedListener<TCEvent>): Promise<this>;
once<TCEvent extends TypedContractEvent>(event: TCEvent, listener: TypedListener<TCEvent>): Promise<this>;
once<TCEvent extends TypedContractEvent>(filter: TypedDeferredTopicFilter<TCEvent>, listener: TypedListener<TCEvent>): Promise<this>;
listeners<TCEvent extends TypedContractEvent>(event: TCEvent): Promise<Array<TypedListener<TCEvent>>>;
listeners(eventName?: string): Promise<Array<Listener>>;
removeAllListeners<TCEvent extends TypedContractEvent>(event?: TCEvent): Promise<this>;
ABI: TypedContractMethod<[
node: BytesLike,
contentTypes: BigNumberish
], [
[bigint, string]
], "view">;
"addr(bytes32)": TypedContractMethod<[node: BytesLike], [string], "view">;
"addr(bytes32,uint256)": TypedContractMethod<[
node: BytesLike,
coinType: BigNumberish
], [
string
], "view">;
approve: TypedContractMethod<[
node: BytesLike,
delegate: AddressLike,
approved: boolean
], [
void
], "nonpayable">;
clearRecords: TypedContractMethod<[node: BytesLike], [void], "nonpayable">;
contenthash: TypedContractMethod<[node: BytesLike], [string], "view">;
dnsRecord: TypedContractMethod<[
node: BytesLike,
name: BytesLike,
resource: BigNumberish
], [
string
], "view">;
hasDNSRecords: TypedContractMethod<[
node: BytesLike,
name: BytesLike
], [
boolean
], "view">;
interfaceImplementer: TypedContractMethod<[
node: BytesLike,
interfaceID: BytesLike
], [
string
], "view">;
isApprovedFor: TypedContractMethod<[
owner: AddressLike,
node: BytesLike,
delegate: AddressLike
], [
boolean
], "view">;
isApprovedForAll: TypedContractMethod<[
account: AddressLike,
operator: AddressLike
], [
boolean
], "view">;
multicall: TypedContractMethod<[data: BytesLike[]], [string[]], "nonpayable">;
multicallWithNodeCheck: TypedContractMethod<[
nodehash: BytesLike,
data: BytesLike[]
], [
string[]
], "nonpayable">;
name: TypedContractMethod<[node: BytesLike], [string], "view">;
pubkey: TypedContractMethod<[
node: BytesLike
], [
[string, string] & {
x: string;
y: string;
}
], "view">;
recordVersions: TypedContractMethod<[arg0: BytesLike], [bigint], "view">;
setABI: TypedContractMethod<[
node: BytesLike,
contentType: BigNumberish,
data: BytesLike
], [
void
], "nonpayable">;
"setAddr(bytes32,uint256,bytes)": TypedContractMethod<[
node: BytesLike,
coinType: BigNumberish,
a: BytesLike
], [
void
], "nonpayable">;
"setAddr(bytes32,address)": TypedContractMethod<[
node: BytesLike,
a: AddressLike
], [
void
], "nonpayable">;
setApprovalForAll: TypedContractMethod<[
operator: AddressLike,
approved: boolean
], [
void
], "nonpayable">;
setContenthash: TypedContractMethod<[
node: BytesLike,
hash: BytesLike
], [
void
], "nonpayable">;
setDNSRecords: TypedContractMethod<[
node: BytesLike,
data: BytesLike
], [
void
], "nonpayable">;
setInterface: TypedContractMethod<[
node: BytesLike,
interfaceID: BytesLike,
implementer: AddressLike
], [
void
], "nonpayable">;
setName: TypedContractMethod<[
node: BytesLike,
newName: string
], [
void
], "nonpayable">;
setPubkey: TypedContractMethod<[
node: BytesLike,
x: BytesLike,
y: BytesLike
], [
void
], "nonpayable">;
setText: TypedContractMethod<[
node: BytesLike,
key: string,
value: string
], [
void
], "nonpayable">;
setZonehash: TypedContractMethod<[
node: BytesLike,
hash: BytesLike
], [
void
], "nonpayable">;
supportsInterface: TypedContractMethod<[
interfaceID: BytesLike
], [
boolean
], "view">;
text: TypedContractMethod<[node: BytesLike, key: string], [string], "view">;
zonehash: TypedContractMethod<[node: BytesLike], [string], "view">;
getFunction<T extends ContractMethod = ContractMethod>(key: string | FunctionFragment): T;
getFunction(nameOrSignature: "ABI"): TypedContractMethod<[
node: BytesLike,
contentTypes: BigNumberish
], [
[bigint, string]
], "view">;
getFunction(nameOrSignature: "addr(bytes32)"): TypedContractMethod<[node: BytesLike], [string], "view">;
getFunction(nameOrSignature: "addr(bytes32,uint256)"): TypedContractMethod<[
node: BytesLike,
coinType: BigNumberish
], [
string
], "view">;
getFunction(nameOrSignature: "approve"): TypedContractMethod<[
node: BytesLike,
delegate: AddressLike,
approved: boolean
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "clearRecords"): TypedContractMethod<[node: BytesLike], [void], "nonpayable">;
getFunction(nameOrSignature: "contenthash"): TypedContractMethod<[node: BytesLike], [string], "view">;
getFunction(nameOrSignature: "dnsRecord"): TypedContractMethod<[
node: BytesLike,
name: BytesLike,
resource: BigNumberish
], [
string
], "view">;
getFunction(nameOrSignature: "hasDNSRecords"): TypedContractMethod<[node: BytesLike, name: BytesLike], [boolean], "view">;
getFunction(nameOrSignature: "interfaceImplementer"): TypedContractMethod<[
node: BytesLike,
interfaceID: BytesLike
], [
string
], "view">;
getFunction(nameOrSignature: "isApprovedFor"): TypedContractMethod<[
owner: AddressLike,
node: BytesLike,
delegate: AddressLike
], [
boolean
], "view">;
getFunction(nameOrSignature: "isApprovedForAll"): TypedContractMethod<[
account: AddressLike,
operator: AddressLike
], [
boolean
], "view">;
getFunction(nameOrSignature: "multicall"): TypedContractMethod<[data: BytesLike[]], [string[]], "nonpayable">;
getFunction(nameOrSignature: "multicallWithNodeCheck"): TypedContractMethod<[
nodehash: BytesLike,
data: BytesLike[]
], [
string[]
], "nonpayable">;
getFunction(nameOrSignature: "name"): TypedContractMethod<[node: BytesLike], [string], "view">;
getFunction(nameOrSignature: "pubkey"): TypedContractMethod<[
node: BytesLike
], [
[string, string] & {
x: string;
y: string;
}
], "view">;
getFunction(nameOrSignature: "recordVersions"): TypedContractMethod<[arg0: BytesLike], [bigint], "view">;
getFunction(nameOrSignature: "setABI"): TypedContractMethod<[
node: BytesLike,
contentType: BigNumberish,
data: BytesLike
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "setAddr(bytes32,uint256,bytes)"): TypedContractMethod<[
node: BytesLike,
coinType: BigNumberish,
a: BytesLike
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "setAddr(bytes32,address)"): TypedContractMethod<[
node: BytesLike,
a: AddressLike
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "setApprovalForAll"): TypedContractMethod<[
operator: AddressLike,
approved: boolean
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "setContenthash"): TypedContractMethod<[
node: BytesLike,
hash: BytesLike
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "setDNSRecords"): TypedContractMethod<[
node: BytesLike,
data: BytesLike
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "setInterface"): TypedContractMethod<[
node: BytesLike,
interfaceID: BytesLike,
implementer: AddressLike
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "setName"): TypedContractMethod<[
node: BytesLike,
newName: string
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "setPubkey"): TypedContractMethod<[
node: BytesLike,
x: BytesLike,
y: BytesLike
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "setText"): TypedContractMethod<[
node: BytesLike,
key: string,
value: string
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "setZonehash"): TypedContractMethod<[
node: BytesLike,
hash: BytesLike
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "supportsInterface"): TypedContractMethod<[interfaceID: BytesLike], [boolean], "view">;
getFunction(nameOrSignature: "text"): TypedContractMethod<[node: BytesLike, key: string], [string], "view">;
getFunction(nameOrSignature: "zonehash"): TypedContractMethod<[node: BytesLike], [string], "view">;
getEvent(key: "ABIChanged"): TypedContractEvent<ABIChangedEvent.InputTuple, ABIChangedEvent.OutputTuple, ABIChangedEvent.OutputObject>;
getEvent(key: "AddrChanged"): TypedContractEvent<AddrChangedEvent.InputTuple, AddrChangedEvent.OutputTuple, AddrChangedEvent.OutputObject>;
getEvent(key: "AddressChanged"): TypedContractEvent<AddressChangedEvent.InputTuple, AddressChangedEvent.OutputTuple, AddressChangedEvent.OutputObject>;
getEvent(key: "ApprovalForAll"): TypedContractEvent<ApprovalForAllEvent.InputTuple, ApprovalForAllEvent.OutputTuple, ApprovalForAllEvent.OutputObject>;
getEvent(key: "Approved"): TypedContractEvent<ApprovedEvent.InputTuple, ApprovedEvent.OutputTuple, ApprovedEvent.OutputObject>;
getEvent(key: "ContenthashChanged"): TypedContractEvent<ContenthashChangedEvent.InputTuple, ContenthashChangedEvent.OutputTuple, ContenthashChangedEvent.OutputObject>;
getEvent(key: "DNSRecordChanged"): TypedContractEvent<DNSRecordChangedEvent.InputTuple, DNSRecordChangedEvent.OutputTuple, DNSRecordChangedEvent.OutputObject>;
getEvent(key: "DNSRecordDeleted"): TypedContractEvent<DNSRecordDeletedEvent.InputTuple, DNSRecordDeletedEvent.OutputTuple, DNSRecordDeletedEvent.OutputObject>;
getEvent(key: "DNSZonehashChanged"): TypedContractEvent<DNSZonehashChangedEvent.InputTuple, DNSZonehashChangedEvent.OutputTuple, DNSZonehashChangedEvent.OutputObject>;
getEvent(key: "InterfaceChanged"): TypedContractEvent<InterfaceChangedEvent.InputTuple, InterfaceChangedEvent.OutputTuple, InterfaceChangedEvent.OutputObject>;
getEvent(key: "NameChanged"): TypedContractEvent<NameChangedEvent.InputTuple, NameChangedEvent.OutputTuple, NameChangedEvent.OutputObject>;
getEvent(key: "PubkeyChanged"): TypedContractEvent<PubkeyChangedEvent.InputTuple, PubkeyChangedEvent.OutputTuple, PubkeyChangedEvent.OutputObject>;
getEvent(key: "TextChanged"): TypedContractEvent<TextChangedEvent.InputTuple, TextChangedEvent.OutputTuple, TextChangedEvent.OutputObject>;
getEvent(key: "VersionChanged"): TypedContractEvent<VersionChangedEvent.InputTuple, VersionChangedEvent.OutputTuple, VersionChangedEvent.OutputObject>;
filters: {
"ABIChanged(bytes32,uint256)": TypedContractEvent<ABIChangedEvent.InputTuple, ABIChangedEvent.OutputTuple, ABIChangedEvent.OutputObject>;
ABIChanged: TypedContractEvent<ABIChangedEvent.InputTuple, ABIChangedEvent.OutputTuple, ABIChangedEvent.OutputObject>;
"AddrChanged(bytes32,address)": TypedContractEvent<AddrChangedEvent.InputTuple, AddrChangedEvent.OutputTuple, AddrChangedEvent.OutputObject>;
AddrChanged: TypedContractEvent<AddrChangedEvent.InputTuple, AddrChangedEvent.OutputTuple, AddrChangedEvent.OutputObject>;
"AddressChanged(bytes32,uint256,bytes)": TypedContractEvent<AddressChangedEvent.InputTuple, AddressChangedEvent.OutputTuple, AddressChangedEvent.OutputObject>;
AddressChanged: TypedContractEvent<AddressChangedEvent.InputTuple, AddressChangedEvent.OutputTuple, AddressChangedEvent.OutputObject>;
"ApprovalForAll(address,address,bool)": TypedContractEvent<ApprovalForAllEvent.InputTuple, ApprovalForAllEvent.OutputTuple, ApprovalForAllEvent.OutputObject>;
ApprovalForAll: TypedContractEvent<ApprovalForAllEvent.InputTuple, ApprovalForAllEvent.OutputTuple, ApprovalForAllEvent.OutputObject>;
"Approved(address,bytes32,address,bool)": TypedContractEvent<ApprovedEvent.InputTuple, ApprovedEvent.OutputTuple, ApprovedEvent.OutputObject>;
Approved: TypedContractEvent<ApprovedEvent.InputTuple, ApprovedEvent.OutputTuple, ApprovedEvent.OutputObject>;
"ContenthashChanged(bytes32,bytes)": TypedContractEvent<ContenthashChangedEvent.InputTuple, ContenthashChangedEvent.OutputTuple, ContenthashChangedEvent.OutputObject>;
ContenthashChanged: TypedContractEvent<ContenthashChangedEvent.InputTuple, ContenthashChangedEvent.OutputTuple, ContenthashChangedEvent.OutputObject>;
"DNSRecordChanged(bytes32,bytes,uint16,bytes)": TypedContractEvent<DNSRecordChangedEvent.InputTuple, DNSRecordChangedEvent.OutputTuple, DNSRecordChangedEvent.OutputObject>;
DNSRecordChanged: TypedContractEvent<DNSRecordChangedEvent.InputTuple, DNSRecordChangedEvent.OutputTuple, DNSRecordChangedEvent.OutputObject>;
"DNSRecordDeleted(bytes32,bytes,uint16)": TypedContractEvent<DNSRecordDeletedEvent.InputTuple, DNSRecordDeletedEvent.OutputTuple, DNSRecordDeletedEvent.OutputObject>;
DNSRecordDeleted: TypedContractEvent<DNSRecordDeletedEvent.InputTuple, DNSRecordDeletedEvent.OutputTuple, DNSRecordDeletedEvent.OutputObject>;
"DNSZonehashChanged(bytes32,bytes,bytes)": TypedContractEvent<DNSZonehashChangedEvent.InputTuple, DNSZonehashChangedEvent.OutputTuple, DNSZonehashChangedEvent.OutputObject>;
DNSZonehashChanged: TypedContractEvent<DNSZonehashChangedEvent.InputTuple, DNSZonehashChangedEvent.OutputTuple, DNSZonehashChangedEvent.OutputObject>;
"InterfaceChanged(bytes32,bytes4,address)": TypedContractEvent<InterfaceChangedEvent.InputTuple, InterfaceChangedEvent.OutputTuple, InterfaceChangedEvent.OutputObject>;
InterfaceChanged: TypedContractEvent<InterfaceChangedEvent.InputTuple, InterfaceChangedEvent.OutputTuple, InterfaceChangedEvent.OutputObject>;
"NameChanged(bytes32,string)": TypedContractEvent<NameChangedEvent.InputTuple, NameChangedEvent.OutputTuple, NameChangedEvent.OutputObject>;
NameChanged: TypedContractEvent<NameChangedEvent.InputTuple, NameChangedEvent.OutputTuple, NameChangedEvent.OutputObject>;
"PubkeyChanged(bytes32,bytes32,bytes32)": TypedContractEvent<PubkeyChangedEvent.InputTuple, PubkeyChangedEvent.OutputTuple, PubkeyChangedEvent.OutputObject>;
PubkeyChanged: TypedContractEvent<PubkeyChangedEvent.InputTuple, PubkeyChangedEvent.OutputTuple, PubkeyChangedEvent.OutputObject>;
"TextChanged(bytes32,string,string,string)": TypedContractEvent<TextChangedEvent.InputTuple, TextChangedEvent.OutputTuple, TextChangedEvent.OutputObject>;
TextChanged: TypedContractEvent<TextChangedEvent.InputTuple, TextChangedEvent.OutputTuple, TextChangedEvent.OutputObject>;
"VersionChanged(bytes32,uint64)": TypedContractEvent<VersionChangedEvent.InputTuple, VersionChangedEvent.OutputTuple, VersionChangedEvent.OutputObject>;
VersionChanged: TypedContractEvent<VersionChangedEvent.InputTuple, VersionChangedEvent.OutputTuple, VersionChangedEvent.OutputObject>;
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,337 @@
import { type ContractRunner } from "ethers";
import type { ENSRegistry, ENSRegistryInterface } from "../ENSRegistry";
export declare class ENSRegistry__factory {
static readonly abi: readonly [{
readonly inputs: readonly [{
readonly internalType: "contract ENS";
readonly name: "_old";
readonly type: "address";
}];
readonly payable: false;
readonly stateMutability: "nonpayable";
readonly type: "constructor";
}, {
readonly anonymous: false;
readonly inputs: readonly [{
readonly indexed: true;
readonly internalType: "address";
readonly name: "owner";
readonly type: "address";
}, {
readonly indexed: true;
readonly internalType: "address";
readonly name: "operator";
readonly type: "address";
}, {
readonly indexed: false;
readonly internalType: "bool";
readonly name: "approved";
readonly type: "bool";
}];
readonly name: "ApprovalForAll";
readonly type: "event";
}, {
readonly anonymous: false;
readonly inputs: readonly [{
readonly indexed: true;
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly indexed: true;
readonly internalType: "bytes32";
readonly name: "label";
readonly type: "bytes32";
}, {
readonly indexed: false;
readonly internalType: "address";
readonly name: "owner";
readonly type: "address";
}];
readonly name: "NewOwner";
readonly type: "event";
}, {
readonly anonymous: false;
readonly inputs: readonly [{
readonly indexed: true;
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly indexed: false;
readonly internalType: "address";
readonly name: "resolver";
readonly type: "address";
}];
readonly name: "NewResolver";
readonly type: "event";
}, {
readonly anonymous: false;
readonly inputs: readonly [{
readonly indexed: true;
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly indexed: false;
readonly internalType: "uint64";
readonly name: "ttl";
readonly type: "uint64";
}];
readonly name: "NewTTL";
readonly type: "event";
}, {
readonly anonymous: false;
readonly inputs: readonly [{
readonly indexed: true;
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly indexed: false;
readonly internalType: "address";
readonly name: "owner";
readonly type: "address";
}];
readonly name: "Transfer";
readonly type: "event";
}, {
readonly constant: true;
readonly inputs: readonly [{
readonly internalType: "address";
readonly name: "owner";
readonly type: "address";
}, {
readonly internalType: "address";
readonly name: "operator";
readonly type: "address";
}];
readonly name: "isApprovedForAll";
readonly outputs: readonly [{
readonly internalType: "bool";
readonly name: "";
readonly type: "bool";
}];
readonly payable: false;
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly constant: true;
readonly inputs: readonly [];
readonly name: "old";
readonly outputs: readonly [{
readonly internalType: "contract ENS";
readonly name: "";
readonly type: "address";
}];
readonly payable: false;
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly constant: true;
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}];
readonly name: "owner";
readonly outputs: readonly [{
readonly internalType: "address";
readonly name: "";
readonly type: "address";
}];
readonly payable: false;
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly constant: true;
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}];
readonly name: "recordExists";
readonly outputs: readonly [{
readonly internalType: "bool";
readonly name: "";
readonly type: "bool";
}];
readonly payable: false;
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly constant: true;
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}];
readonly name: "resolver";
readonly outputs: readonly [{
readonly internalType: "address";
readonly name: "";
readonly type: "address";
}];
readonly payable: false;
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly constant: false;
readonly inputs: readonly [{
readonly internalType: "address";
readonly name: "operator";
readonly type: "address";
}, {
readonly internalType: "bool";
readonly name: "approved";
readonly type: "bool";
}];
readonly name: "setApprovalForAll";
readonly outputs: readonly [];
readonly payable: false;
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly constant: false;
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "address";
readonly name: "owner";
readonly type: "address";
}];
readonly name: "setOwner";
readonly outputs: readonly [];
readonly payable: false;
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly constant: false;
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "address";
readonly name: "owner";
readonly type: "address";
}, {
readonly internalType: "address";
readonly name: "resolver";
readonly type: "address";
}, {
readonly internalType: "uint64";
readonly name: "ttl";
readonly type: "uint64";
}];
readonly name: "setRecord";
readonly outputs: readonly [];
readonly payable: false;
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly constant: false;
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "address";
readonly name: "resolver";
readonly type: "address";
}];
readonly name: "setResolver";
readonly outputs: readonly [];
readonly payable: false;
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly constant: false;
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "bytes32";
readonly name: "label";
readonly type: "bytes32";
}, {
readonly internalType: "address";
readonly name: "owner";
readonly type: "address";
}];
readonly name: "setSubnodeOwner";
readonly outputs: readonly [{
readonly internalType: "bytes32";
readonly name: "";
readonly type: "bytes32";
}];
readonly payable: false;
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly constant: false;
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "bytes32";
readonly name: "label";
readonly type: "bytes32";
}, {
readonly internalType: "address";
readonly name: "owner";
readonly type: "address";
}, {
readonly internalType: "address";
readonly name: "resolver";
readonly type: "address";
}, {
readonly internalType: "uint64";
readonly name: "ttl";
readonly type: "uint64";
}];
readonly name: "setSubnodeRecord";
readonly outputs: readonly [];
readonly payable: false;
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly constant: false;
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "uint64";
readonly name: "ttl";
readonly type: "uint64";
}];
readonly name: "setTTL";
readonly outputs: readonly [];
readonly payable: false;
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly constant: true;
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}];
readonly name: "ttl";
readonly outputs: readonly [{
readonly internalType: "uint64";
readonly name: "";
readonly type: "uint64";
}];
readonly payable: false;
readonly stateMutability: "view";
readonly type: "function";
}];
static createInterface(): ENSRegistryInterface;
static connect(address: string, runner?: ContractRunner | null): ENSRegistry;
}

View File

@@ -0,0 +1,789 @@
import { type ContractRunner } from "ethers";
import type { ENSResolver, ENSResolverInterface } from "../ENSResolver";
export declare class ENSResolver__factory {
static readonly abi: readonly [{
readonly inputs: readonly [{
readonly internalType: "contract ENS";
readonly name: "_ens";
readonly type: "address";
}, {
readonly internalType: "contract INameWrapper";
readonly name: "wrapperAddress";
readonly type: "address";
}, {
readonly internalType: "address";
readonly name: "_trustedETHController";
readonly type: "address";
}, {
readonly internalType: "address";
readonly name: "_trustedReverseRegistrar";
readonly type: "address";
}];
readonly stateMutability: "nonpayable";
readonly type: "constructor";
}, {
readonly anonymous: false;
readonly inputs: readonly [{
readonly indexed: true;
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly indexed: true;
readonly internalType: "uint256";
readonly name: "contentType";
readonly type: "uint256";
}];
readonly name: "ABIChanged";
readonly type: "event";
}, {
readonly anonymous: false;
readonly inputs: readonly [{
readonly indexed: true;
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly indexed: false;
readonly internalType: "address";
readonly name: "a";
readonly type: "address";
}];
readonly name: "AddrChanged";
readonly type: "event";
}, {
readonly anonymous: false;
readonly inputs: readonly [{
readonly indexed: true;
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly indexed: false;
readonly internalType: "uint256";
readonly name: "coinType";
readonly type: "uint256";
}, {
readonly indexed: false;
readonly internalType: "bytes";
readonly name: "newAddress";
readonly type: "bytes";
}];
readonly name: "AddressChanged";
readonly type: "event";
}, {
readonly anonymous: false;
readonly inputs: readonly [{
readonly indexed: true;
readonly internalType: "address";
readonly name: "owner";
readonly type: "address";
}, {
readonly indexed: true;
readonly internalType: "address";
readonly name: "operator";
readonly type: "address";
}, {
readonly indexed: false;
readonly internalType: "bool";
readonly name: "approved";
readonly type: "bool";
}];
readonly name: "ApprovalForAll";
readonly type: "event";
}, {
readonly anonymous: false;
readonly inputs: readonly [{
readonly indexed: false;
readonly internalType: "address";
readonly name: "owner";
readonly type: "address";
}, {
readonly indexed: true;
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly indexed: true;
readonly internalType: "address";
readonly name: "delegate";
readonly type: "address";
}, {
readonly indexed: true;
readonly internalType: "bool";
readonly name: "approved";
readonly type: "bool";
}];
readonly name: "Approved";
readonly type: "event";
}, {
readonly anonymous: false;
readonly inputs: readonly [{
readonly indexed: true;
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly indexed: false;
readonly internalType: "bytes";
readonly name: "hash";
readonly type: "bytes";
}];
readonly name: "ContenthashChanged";
readonly type: "event";
}, {
readonly anonymous: false;
readonly inputs: readonly [{
readonly indexed: true;
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly indexed: false;
readonly internalType: "bytes";
readonly name: "name";
readonly type: "bytes";
}, {
readonly indexed: false;
readonly internalType: "uint16";
readonly name: "resource";
readonly type: "uint16";
}, {
readonly indexed: false;
readonly internalType: "bytes";
readonly name: "record";
readonly type: "bytes";
}];
readonly name: "DNSRecordChanged";
readonly type: "event";
}, {
readonly anonymous: false;
readonly inputs: readonly [{
readonly indexed: true;
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly indexed: false;
readonly internalType: "bytes";
readonly name: "name";
readonly type: "bytes";
}, {
readonly indexed: false;
readonly internalType: "uint16";
readonly name: "resource";
readonly type: "uint16";
}];
readonly name: "DNSRecordDeleted";
readonly type: "event";
}, {
readonly anonymous: false;
readonly inputs: readonly [{
readonly indexed: true;
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly indexed: false;
readonly internalType: "bytes";
readonly name: "lastzonehash";
readonly type: "bytes";
}, {
readonly indexed: false;
readonly internalType: "bytes";
readonly name: "zonehash";
readonly type: "bytes";
}];
readonly name: "DNSZonehashChanged";
readonly type: "event";
}, {
readonly anonymous: false;
readonly inputs: readonly [{
readonly indexed: true;
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly indexed: true;
readonly internalType: "bytes4";
readonly name: "interfaceID";
readonly type: "bytes4";
}, {
readonly indexed: false;
readonly internalType: "address";
readonly name: "implementer";
readonly type: "address";
}];
readonly name: "InterfaceChanged";
readonly type: "event";
}, {
readonly anonymous: false;
readonly inputs: readonly [{
readonly indexed: true;
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly indexed: false;
readonly internalType: "string";
readonly name: "name";
readonly type: "string";
}];
readonly name: "NameChanged";
readonly type: "event";
}, {
readonly anonymous: false;
readonly inputs: readonly [{
readonly indexed: true;
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly indexed: false;
readonly internalType: "bytes32";
readonly name: "x";
readonly type: "bytes32";
}, {
readonly indexed: false;
readonly internalType: "bytes32";
readonly name: "y";
readonly type: "bytes32";
}];
readonly name: "PubkeyChanged";
readonly type: "event";
}, {
readonly anonymous: false;
readonly inputs: readonly [{
readonly indexed: true;
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly indexed: true;
readonly internalType: "string";
readonly name: "indexedKey";
readonly type: "string";
}, {
readonly indexed: false;
readonly internalType: "string";
readonly name: "key";
readonly type: "string";
}, {
readonly indexed: false;
readonly internalType: "string";
readonly name: "value";
readonly type: "string";
}];
readonly name: "TextChanged";
readonly type: "event";
}, {
readonly anonymous: false;
readonly inputs: readonly [{
readonly indexed: true;
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly indexed: false;
readonly internalType: "uint64";
readonly name: "newVersion";
readonly type: "uint64";
}];
readonly name: "VersionChanged";
readonly type: "event";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "uint256";
readonly name: "contentTypes";
readonly type: "uint256";
}];
readonly name: "ABI";
readonly outputs: readonly [{
readonly internalType: "uint256";
readonly name: "";
readonly type: "uint256";
}, {
readonly internalType: "bytes";
readonly name: "";
readonly type: "bytes";
}];
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}];
readonly name: "addr";
readonly outputs: readonly [{
readonly internalType: "address payable";
readonly name: "";
readonly type: "address";
}];
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "uint256";
readonly name: "coinType";
readonly type: "uint256";
}];
readonly name: "addr";
readonly outputs: readonly [{
readonly internalType: "bytes";
readonly name: "";
readonly type: "bytes";
}];
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "address";
readonly name: "delegate";
readonly type: "address";
}, {
readonly internalType: "bool";
readonly name: "approved";
readonly type: "bool";
}];
readonly name: "approve";
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}];
readonly name: "clearRecords";
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}];
readonly name: "contenthash";
readonly outputs: readonly [{
readonly internalType: "bytes";
readonly name: "";
readonly type: "bytes";
}];
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "bytes32";
readonly name: "name";
readonly type: "bytes32";
}, {
readonly internalType: "uint16";
readonly name: "resource";
readonly type: "uint16";
}];
readonly name: "dnsRecord";
readonly outputs: readonly [{
readonly internalType: "bytes";
readonly name: "";
readonly type: "bytes";
}];
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "bytes32";
readonly name: "name";
readonly type: "bytes32";
}];
readonly name: "hasDNSRecords";
readonly outputs: readonly [{
readonly internalType: "bool";
readonly name: "";
readonly type: "bool";
}];
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "bytes4";
readonly name: "interfaceID";
readonly type: "bytes4";
}];
readonly name: "interfaceImplementer";
readonly outputs: readonly [{
readonly internalType: "address";
readonly name: "";
readonly type: "address";
}];
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "address";
readonly name: "owner";
readonly type: "address";
}, {
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "address";
readonly name: "delegate";
readonly type: "address";
}];
readonly name: "isApprovedFor";
readonly outputs: readonly [{
readonly internalType: "bool";
readonly name: "";
readonly type: "bool";
}];
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "address";
readonly name: "account";
readonly type: "address";
}, {
readonly internalType: "address";
readonly name: "operator";
readonly type: "address";
}];
readonly name: "isApprovedForAll";
readonly outputs: readonly [{
readonly internalType: "bool";
readonly name: "";
readonly type: "bool";
}];
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes[]";
readonly name: "data";
readonly type: "bytes[]";
}];
readonly name: "multicall";
readonly outputs: readonly [{
readonly internalType: "bytes[]";
readonly name: "results";
readonly type: "bytes[]";
}];
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "nodehash";
readonly type: "bytes32";
}, {
readonly internalType: "bytes[]";
readonly name: "data";
readonly type: "bytes[]";
}];
readonly name: "multicallWithNodeCheck";
readonly outputs: readonly [{
readonly internalType: "bytes[]";
readonly name: "results";
readonly type: "bytes[]";
}];
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}];
readonly name: "name";
readonly outputs: readonly [{
readonly internalType: "string";
readonly name: "";
readonly type: "string";
}];
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}];
readonly name: "pubkey";
readonly outputs: readonly [{
readonly internalType: "bytes32";
readonly name: "x";
readonly type: "bytes32";
}, {
readonly internalType: "bytes32";
readonly name: "y";
readonly type: "bytes32";
}];
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "";
readonly type: "bytes32";
}];
readonly name: "recordVersions";
readonly outputs: readonly [{
readonly internalType: "uint64";
readonly name: "";
readonly type: "uint64";
}];
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "uint256";
readonly name: "contentType";
readonly type: "uint256";
}, {
readonly internalType: "bytes";
readonly name: "data";
readonly type: "bytes";
}];
readonly name: "setABI";
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "uint256";
readonly name: "coinType";
readonly type: "uint256";
}, {
readonly internalType: "bytes";
readonly name: "a";
readonly type: "bytes";
}];
readonly name: "setAddr";
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "address";
readonly name: "a";
readonly type: "address";
}];
readonly name: "setAddr";
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "address";
readonly name: "operator";
readonly type: "address";
}, {
readonly internalType: "bool";
readonly name: "approved";
readonly type: "bool";
}];
readonly name: "setApprovalForAll";
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "bytes";
readonly name: "hash";
readonly type: "bytes";
}];
readonly name: "setContenthash";
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "bytes";
readonly name: "data";
readonly type: "bytes";
}];
readonly name: "setDNSRecords";
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "bytes4";
readonly name: "interfaceID";
readonly type: "bytes4";
}, {
readonly internalType: "address";
readonly name: "implementer";
readonly type: "address";
}];
readonly name: "setInterface";
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "string";
readonly name: "newName";
readonly type: "string";
}];
readonly name: "setName";
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "bytes32";
readonly name: "x";
readonly type: "bytes32";
}, {
readonly internalType: "bytes32";
readonly name: "y";
readonly type: "bytes32";
}];
readonly name: "setPubkey";
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "string";
readonly name: "key";
readonly type: "string";
}, {
readonly internalType: "string";
readonly name: "value";
readonly type: "string";
}];
readonly name: "setText";
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "bytes";
readonly name: "hash";
readonly type: "bytes";
}];
readonly name: "setZonehash";
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes4";
readonly name: "interfaceID";
readonly type: "bytes4";
}];
readonly name: "supportsInterface";
readonly outputs: readonly [{
readonly internalType: "bool";
readonly name: "";
readonly type: "bool";
}];
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}, {
readonly internalType: "string";
readonly name: "key";
readonly type: "string";
}];
readonly name: "text";
readonly outputs: readonly [{
readonly internalType: "string";
readonly name: "";
readonly type: "string";
}];
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly internalType: "bytes32";
readonly name: "node";
readonly type: "bytes32";
}];
readonly name: "zonehash";
readonly outputs: readonly [{
readonly internalType: "bytes";
readonly name: "";
readonly type: "bytes";
}];
readonly stateMutability: "view";
readonly type: "function";
}];
static createInterface(): ENSResolverInterface;
static connect(address: string, runner?: ContractRunner | null): ENSResolver;
}

View File

@@ -1,6 +1,8 @@
export { ENS__factory } from "./ENS__factory";
export { ENSNameWrapper__factory } from "./ENSNameWrapper__factory";
export { ENSRegistry__factory } from "./ENSRegistry__factory";
export { ENSResolver__factory } from "./ENSResolver__factory";
export { ERC20__factory } from "./ERC20__factory";
export { GasPriceOracle__factory } from "./GasPriceOracle__factory";
export { Multicall__factory } from "./Multicall__factory";
export { OffchainOracle__factory } from "./OffchainOracle__factory";
export { OvmGasPriceOracle__factory } from "./OvmGasPriceOracle__factory";

View File

@@ -1,14 +1,18 @@
export type { ENS } from "./ENS";
export type { ENSNameWrapper } from "./ENSNameWrapper";
export type { ENSRegistry } from "./ENSRegistry";
export type { ENSResolver } from "./ENSResolver";
export type { ERC20 } from "./ERC20";
export type { GasPriceOracle } from "./GasPriceOracle";
export type { Multicall } from "./Multicall";
export type { OffchainOracle } from "./OffchainOracle";
export type { OvmGasPriceOracle } from "./OvmGasPriceOracle";
export type { ReverseRecords } from "./ReverseRecords";
export * as factories from "./factories";
export { ENS__factory } from "./factories/ENS__factory";
export { ENSNameWrapper__factory } from "./factories/ENSNameWrapper__factory";
export { ENSRegistry__factory } from "./factories/ENSRegistry__factory";
export { ENSResolver__factory } from "./factories/ENSResolver__factory";
export { ERC20__factory } from "./factories/ERC20__factory";
export { GasPriceOracle__factory } from "./factories/GasPriceOracle__factory";
export { Multicall__factory } from "./factories/Multicall__factory";
export { OffchainOracle__factory } from "./factories/OffchainOracle__factory";
export { OvmGasPriceOracle__factory } from "./factories/OvmGasPriceOracle__factory";

8
dist/utils.d.ts vendored
View File

@@ -1,5 +1,3 @@
/// <reference types="node" />
/// <reference types="node" />
import { webcrypto } from 'crypto';
import BN from 'bn.js';
import type { BigNumberish } from 'ethers';
@@ -22,6 +20,12 @@ export declare function leInt2Buff(bigint: bnInput | bigint): Uint8Array;
export declare function toFixedHex(numberish: BigNumberish, length?: number): string;
export declare function toFixedLength(string: string, length?: number): string;
export declare function rBigInt(nbytes?: number): bigint;
export declare function rHex(nbytes?: number): string;
export declare function bigIntReplacer(key: any, value: any): any;
export declare function substring(str: string, length?: number): string;
export declare function digest(bytes: Uint8Array, algo?: string): Promise<Uint8Array>;
export declare function numberFormatter(num: string | number | bigint, digits?: number): string;
export declare function isHex(value: string): boolean;
export declare function toContentHash(ipfsUrl: string): any;
export declare function fromContentHash(contentHash: string): any;
export {};

29
dist/websnark.d.ts vendored
View File

@@ -1,28 +1,27 @@
import type { Element } from '@tornado/fixed-merkle-tree';
import type { AddressLike, BytesLike, BigNumberish } from 'ethers';
export type snarkInputs = {
import type { Element } from 'fixed-merkle-tree';
export interface snarkInputs {
root: Element;
nullifierHex: string;
recipient: AddressLike;
relayer: AddressLike;
recipient: string;
relayer: string;
fee: bigint;
refund: bigint;
nullifier: bigint;
secret: bigint;
pathElements: Element[];
pathIndices: Element[];
};
}
export type snarkArgs = [
_root: BytesLike,
_nullifierHash: BytesLike,
_recipient: AddressLike,
_relayer: AddressLike,
_fee: BigNumberish,
_refund: BigNumberish
_root: string,
_nullifierHash: string,
_recipient: string,
_relayer: string,
_fee: string,
_refund: string
];
export type snarkProofs = {
proof: BytesLike;
export interface snarkProofs {
proof: string;
args: snarkArgs;
};
}
export declare function initGroth16(): Promise<void>;
export declare function calculateSnarkProof(input: snarkInputs, circuit: object, provingKey: ArrayBuffer): Promise<snarkProofs>;

9
dist/zip.d.ts vendored Normal file
View File

@@ -0,0 +1,9 @@
import { AsyncZippable, Unzipped, ZipAttributes } from 'fflate';
export declare function zipAsync(file: AsyncZippable, options?: ZipAttributes): Promise<Uint8Array>;
export declare function unzipAsync(data: Uint8Array): Promise<Unzipped>;
export declare function downloadZip<T>({ staticUrl, zipName, zipDigest, parseJson, }: {
staticUrl?: string;
zipName: string;
zipDigest?: string;
parseJson?: boolean;
}): Promise<T>;

9
hardhat.config.ts Normal file
View File

@@ -0,0 +1,9 @@
import type { HardhatUserConfig } from 'hardhat/types';
import '@nomicfoundation/hardhat-toolbox';
import '@nomicfoundation/hardhat-ethers';
const config: HardhatUserConfig = {
solidity: '0.8.28',
};
export default config;

View File

@@ -1,76 +1,107 @@
{
"name": "@tornado/core",
"version": "1.0.1",
"description": "An SDK for building applications on top of Privacy Pools",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"unpkg": "./dist/index.umd.js",
"jsdelivr": "./dist/index.umd.js",
"scripts": {
"typechain": "typechain --target ethers-v6 --out-dir src/typechain src/abi/*.json",
"types": "tsc --declaration --emitDeclarationOnly",
"lint": "eslint src/**/*.ts --ext .ts --ignore-pattern src/typechain",
"build:node": "rollup -c",
"build:web": "webpack",
"build": "yarn types && yarn build:node && yarn build:web"
},
"author": "",
"license": "MIT",
"files": [
"dist",
"src",
".eslintrc.js",
".gitattributes",
".gitignore",
".npmrc",
"logo.png",
"logo2.png",
"rollup.config.mjs",
"tsconfig.json",
"yarn.lock"
],
"dependencies": {
"@metamask/eth-sig-util": "^7.0.1",
"@tornado/contracts": "^1.0.0",
"@tornado/fixed-merkle-tree": "^0.7.3",
"@tornado/snarkjs": "^0.1.20",
"@tornado/websnark": "^0.0.4",
"ajv": "^8.12.0",
"bn.js": "^5.2.1",
"circomlibjs": "0.1.7",
"cross-fetch": "^4.0.0",
"ethers": "^6.4.0",
"ffjavascript": "0.2.48",
"fflate": "^0.8.2"
},
"optionalDependencies": {},
"devDependencies": {
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.2.3",
"@typechain/ethers-v6": "^0.5.1",
"@types/bn.js": "^5.1.5",
"@types/circomlibjs": "^0.1.6",
"@types/node": "^20.12.5",
"@types/node-fetch": "^2.6.11",
"@typescript-eslint/eslint-plugin": "^7.6.0",
"@typescript-eslint/parser": "^7.6.0",
"esbuild": "^0.20.2",
"esbuild-loader": "^4.1.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-prettier": "^5.1.3",
"node-polyfill-webpack-plugin": "^3.0.0",
"prettier": "^3.2.5",
"rollup": "^4.14.1",
"rollup-plugin-esbuild": "^6.1.1",
"tsc": "^2.0.4",
"typechain": "^8.3.2",
"typescript": "^5.4.4",
"webpack": "^5.91.0",
"webpack-cli": "^5.1.4"
}
"name": "@tornado/core",
"version": "1.0.19",
"description": "An SDK for building applications on top of Privacy Pools",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"unpkg": "./dist/tornado.umd.min.js",
"jsdelivr": "./dist/tornado.umd.min.js",
"scripts": {
"typechain": "typechain --target ethers-v6 --out-dir src/typechain src/abi/*.json",
"types": "tsc --declaration --emitDeclarationOnly -p tsconfig.build.json",
"lint": "eslint src/**/*.ts test/**/*.ts --ext .ts --ignore-pattern src/typechain",
"build:node": "rollup -c",
"build:web": "webpack",
"build:hash": "ts-node scripts/hash.ts",
"build": "yarn types && yarn build:node && yarn build:web && yarn build:hash",
"ipfs:build": "docker build -t tornado-core .",
"ipfs:hash": "docker container run --rm -it --entrypoint cat tornado-core /app/dist/hashes.json",
"test": "nyc mocha --require ts-node/register --require source-map-support/register --recursive 'test/**/*.ts' --timeout '300000'"
},
"author": "",
"license": "MIT",
"files": [
"dist",
"src",
".eslintrc.js",
".gitattributes",
".gitignore",
".npmrc",
"logo.png",
"logo2.png",
"rollup.config.mjs",
"tsconfig.json",
"yarn.lock"
],
"dependencies": {
"@ensdomains/content-hash": "2.5.7",
"@metamask/eth-sig-util": "^8.0.0",
"@tornado/contracts": "git+https://git.tornado.ws/tornadocontrib/tornado-contracts.git#093ae2210e1f1b016b756b4db200c4a1b3308408",
"ajv": "^8.17.1",
"bn.js": "^5.2.1",
"circomlibjs": "0.1.7",
"cross-fetch": "^4.0.0",
"ethers": "^6.13.4",
"ffjavascript": "0.2.48",
"fflate": "^0.8.2",
"fixed-merkle-tree": "0.7.3",
"idb": "^8.0.0",
"snarkjs": "git+https://github.com/MicahZoltu/snarkjs.git#2c964b3fe6019e057acab04cc17705d1f7fdaf9a",
"websnark": "git+https://github.com/MicahZoltu/websnark.git#f0ddbf34b3045cac9e6d3e4d977bf3b439869fae"
},
"devDependencies": {
"@nomicfoundation/hardhat-chai-matchers": "^2.0.7",
"@nomicfoundation/hardhat-ethers": "^3.0.8",
"@nomicfoundation/hardhat-ignition": "^0.15.5",
"@nomicfoundation/hardhat-ignition-ethers": "^0.15.5",
"@nomicfoundation/hardhat-network-helpers": "^1.0.11",
"@nomicfoundation/hardhat-toolbox": "^5.0.0",
"@nomicfoundation/hardhat-verify": "^2.0.10",
"@nomicfoundation/ignition-core": "^0.15.5",
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@typechain/ethers-v6": "^0.5.1",
"@typechain/hardhat": "^9.1.0",
"@types/bn.js": "^5.1.6",
"@types/chai": "^4.2.0",
"@types/circomlibjs": "^0.1.6",
"@types/mocha": "^10.0.9",
"@types/node": "^22.8.0",
"@types/node-fetch": "^2.6.11",
"@typescript-eslint/eslint-plugin": "^8.11.0",
"@typescript-eslint/parser": "^8.11.0",
"chai": "4.5.0",
"esbuild-loader": "^4.2.2",
"eslint": "8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-import-resolver-typescript": "^3.6.3",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-prettier": "^5.2.1",
"fetch-mock": "^12.0.2",
"hardhat": "^2.22.10",
"hardhat-gas-reporter": "^2.2.1",
"mocha": "^10.7.3",
"node-polyfill-webpack-plugin": "^4.0.0",
"nyc": "^17.1.0",
"prettier": "^3.3.3",
"rollup": "^4.24.0",
"rollup-plugin-esbuild": "^6.1.1",
"solidity-coverage": "^0.8.13",
"ts-node": "^10.9.2",
"tsc": "^2.0.4",
"typechain": "^8.3.2",
"typescript": "^5.6.3",
"webpack": "^5.95.0",
"webpack-cli": "^5.1.4"
},
"resolutions": {
"strip-ansi": "6.0.1",
"@adraffy/ens-normalize": "1.10.1",
"@noble/curves": "1.2.0",
"@noble/hashes": "1.3.2",
"big-integer": "1.6.52",
"ffjavascript": "0.2.48"
}
}

View File

@@ -7,81 +7,81 @@ import { readFileSync } from 'fs';
const pkgJson = JSON.parse(readFileSync("./package.json"));
const external = Object.keys(pkgJson.dependencies).concat(
Object.keys(pkgJson.optionalDependencies),
[
'http-proxy-agent',
'https-proxy-agent',
'socks-proxy-agent',
'@tornado/websnark/src/utils',
'@tornado/websnark/src/groth16',
]
Object.keys(pkgJson.optionalDependencies || {}),
[
'http-proxy-agent',
'https-proxy-agent',
'socks-proxy-agent',
'websnark/src/utils',
'websnark/src/groth16',
]
);
const config = [
{
input: 'src/index.ts',
output: [
{
file: pkgJson.main,
format: "cjs",
esModule: false,
},
],
external,
plugins: [
esbuild({
include: /\.[jt]sx?$/,
minify: false,
sourceMap: true,
target: 'es2016',
}),
commonjs(),
nodeResolve(),
json()
],
},
{
input: 'src/index.ts',
output: [
{
file: pkgJson.module,
format: "esm",
},
],
external,
plugins: [
esbuild({
include: /\.[jt]sx?$/,
minify: false,
sourceMap: true,
target: 'es2016',
}),
nodeResolve(),
json()
],
},
{
input: 'src/merkleTreeWorker.ts',
output: [
{
file: 'dist/merkleTreeWorker.js',
format: "cjs",
esModule: false,
},
],
treeshake: 'smallest',
plugins: [
esbuild({
include: /\.[jt]sx?$/,
minify: false,
sourceMap: true,
target: 'es2016',
}),
commonjs(),
nodeResolve(),
json()
],
}
{
input: 'src/index.ts',
output: [
{
file: pkgJson.main,
format: "cjs",
esModule: false,
},
],
external,
plugins: [
esbuild({
include: /\.[jt]sx?$/,
minify: false,
sourceMap: true,
target: 'es2022',
}),
commonjs(),
nodeResolve(),
json()
],
},
{
input: 'src/index.ts',
output: [
{
file: pkgJson.module,
format: "esm",
},
],
external,
plugins: [
esbuild({
include: /\.[jt]sx?$/,
minify: false,
sourceMap: true,
target: 'es2022',
}),
nodeResolve(),
json()
],
},
{
input: 'src/merkleTreeWorker.ts',
output: [
{
file: 'dist/merkleTreeWorker.js',
format: "cjs",
esModule: false,
},
],
treeshake: 'smallest',
plugins: [
esbuild({
include: /\.[jt]sx?$/,
minify: false,
sourceMap: true,
target: 'es2022',
}),
commonjs(),
nodeResolve(),
json()
],
}
]
export default config;

36
scripts/hash.ts Normal file
View File

@@ -0,0 +1,36 @@
import path from 'path'
import { readFile, readdir, writeFile } from 'fs/promises';
import { bytesToBase64, digest } from '../src';
async function content(file: string) {
const content = new Uint8Array(await readFile(file));
const hash = 'sha384-' + bytesToBase64(await digest(content));
return hash;
}
async function hash() {
const staticFiles = await readdir('dist');
const hashes = {} as {
[key: string]: string;
};
for (const filePath of staticFiles) {
const file = path.join('dist', filePath).replaceAll(path.sep, path.posix.sep);
if (!['.js', '.mjs'].includes(path.extname(file))) {
continue;
}
const hash = await content(file);
hashes[file] = hash;
}
await writeFile('dist/hashes.json', JSON.stringify(hashes, null, 2));
console.log('hashes', hashes);
}
hash();

File diff suppressed because one or more lines are too long

1
src/abi/ENSRegistry.json Normal file
View File

@@ -0,0 +1 @@
[{"inputs":[{"internalType":"contract ENS","name":"_old","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"label","type":"bytes32"},{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"NewOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"address","name":"resolver","type":"address"}],"name":"NewResolver","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"ttl","type":"uint64"}],"name":"NewTTL","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"Transfer","type":"event"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"old","outputs":[{"internalType":"contract ENS","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"recordExists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"resolver","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"resolver","type":"address"},{"internalType":"uint64","name":"ttl","type":"uint64"}],"name":"setRecord","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"resolver","type":"address"}],"name":"setResolver","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"label","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"}],"name":"setSubnodeOwner","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"label","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"resolver","type":"address"},{"internalType":"uint64","name":"ttl","type":"uint64"}],"name":"setSubnodeRecord","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint64","name":"ttl","type":"uint64"}],"name":"setTTL","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"ttl","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"}]

1
src/abi/ENSResolver.json Normal file

File diff suppressed because one or more lines are too long

View File

@@ -1,189 +0,0 @@
[
{
"inputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "GAS_UNIT",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint32",
"name": "_derivationThresold",
"type": "uint32"
}
],
"name": "changeDerivationThresold",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint32",
"name": "_gasUnit",
"type": "uint32"
}
],
"name": "changeGasUnit",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint32",
"name": "_heartbeat",
"type": "uint32"
}
],
"name": "changeHeartbeat",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_owner",
"type": "address"
}
],
"name": "changeOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "derivationThresold",
"outputs": [
{
"internalType": "uint32",
"name": "",
"type": "uint32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "gasPrice",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "heartbeat",
"outputs": [
{
"internalType": "uint32",
"name": "",
"type": "uint32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "maxFeePerGas",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "maxPriorityFeePerGas",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "pastGasPrice",
"outputs": [
{
"internalType": "uint32",
"name": "",
"type": "uint32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint32",
"name": "_gasPrice",
"type": "uint32"
}
],
"name": "setGasPrice",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "timestamp",
"outputs": [
{
"internalType": "uint32",
"name": "",
"type": "uint32"
}
],
"stateMutability": "view",
"type": "function"
}
]

View File

@@ -1,339 +1,572 @@
import type { Provider, BlockTag, Block, TransactionResponse, BaseContract, ContractEventName, EventLog } from 'ethers';
import {
Provider,
BlockTag,
Block,
TransactionResponse,
BaseContract,
ContractEventName,
EventLog,
TransactionReceipt,
isHexString,
assert,
assertArgument,
DeferredTopicFilter,
EventFragment,
TopicFilter,
Interface,
UndecodedEventLog,
Log,
} from 'ethers';
import { chunk, sleep } from './utils';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function isDeferred(value: any): value is DeferredTopicFilter {
return (
value &&
typeof value === 'object' &&
'getTopicFilter' in value &&
typeof value.getTopicFilter === 'function' &&
value.fragment
);
}
/**
* Copied from ethers.js as they don't export this function
* https://github.com/ethers-io/ethers.js/blob/main/src.ts/contract/contract.ts#L464
*/
export async function getSubInfo(
abiInterface: Interface,
event: ContractEventName,
): Promise<{
fragment: null | EventFragment;
tag: string;
topics: TopicFilter;
}> {
let topics: Array<null | string | Array<string>>;
let fragment: null | EventFragment = null;
// Convert named events to topicHash and get the fragment for
// events which need deconstructing.
if (Array.isArray(event)) {
const topicHashify = function (name: string): string {
if (isHexString(name, 32)) {
return name;
}
const fragment = abiInterface.getEvent(name);
assertArgument(fragment, 'unknown fragment', 'name', name);
return fragment.topicHash;
};
// Array of Topics and Names; e.g. `[ "0x1234...89ab", "Transfer(address)" ]`
topics = event.map((e) => {
if (e == null) {
return null;
}
if (Array.isArray(e)) {
return e.map(topicHashify);
}
return topicHashify(e);
});
} else if (event === '*') {
topics = [null];
} else if (typeof event === 'string') {
if (isHexString(event, 32)) {
// Topic Hash
topics = [event];
} else {
// Name or Signature; e.g. `"Transfer", `"Transfer(address)"`
fragment = abiInterface.getEvent(event);
assertArgument(fragment, 'unknown fragment', 'event', event);
topics = [fragment.topicHash];
}
} else if (isDeferred(event)) {
// Deferred Topic Filter; e.g. `contract.filter.Transfer(from)`
topics = await event.getTopicFilter();
} else if ('fragment' in event) {
// ContractEvent; e.g. `contract.filter.Transfer`
fragment = event.fragment;
topics = [fragment.topicHash];
} else {
assertArgument(false, 'unknown event name', 'event', event);
}
// Normalize topics and sort TopicSets
topics = topics.map((t) => {
if (t == null) {
return null;
}
if (Array.isArray(t)) {
const items = Array.from(new Set(t.map((t) => t.toLowerCase())).values());
if (items.length === 1) {
return items[0];
}
items.sort();
return items;
}
return t.toLowerCase();
});
const tag = topics
.map((t) => {
if (t == null) {
return 'null';
}
if (Array.isArray(t)) {
return t.join('|');
}
return t;
})
.join('&');
return { fragment, tag, topics };
}
export async function multiQueryFilter(
// Single address will scan for a single contract, array for multiple, and * for all contracts with event topic
address: string | string[],
contract: BaseContract,
event: ContractEventName,
fromBlock?: BlockTag,
toBlock?: BlockTag,
) {
if (fromBlock == null) {
fromBlock = 0;
}
if (toBlock == null) {
toBlock = 'latest';
}
const { fragment, topics } = await getSubInfo(contract.interface, event);
const filter = {
address: address === '*' ? undefined : address,
topics,
fromBlock,
toBlock,
};
const provider = contract.runner as Provider | null;
assert(provider, 'contract runner does not have a provider', 'UNSUPPORTED_OPERATION', { operation: 'queryFilter' });
return (await provider.getLogs(filter)).map((log) => {
let foundFragment = fragment;
if (foundFragment == null) {
try {
foundFragment = contract.interface.getEvent(log.topics[0]);
// eslint-disable-next-line no-empty
} catch {}
}
if (foundFragment) {
try {
return new EventLog(log, contract.interface, foundFragment);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
return new UndecodedEventLog(log, error);
}
}
return new Log(log, provider);
});
}
export interface BatchBlockServiceConstructor {
provider: Provider;
onProgress?: BatchBlockOnProgress;
concurrencySize?: number;
batchSize?: number;
shouldRetry?: boolean;
retryMax?: number;
retryOn?: number;
provider: Provider;
onProgress?: BatchBlockOnProgress;
concurrencySize?: number;
batchSize?: number;
shouldRetry?: boolean;
retryMax?: number;
retryOn?: number;
}
export type BatchBlockOnProgress = ({
percentage,
currentIndex,
totalIndex,
percentage,
currentIndex,
totalIndex,
}: {
percentage: number;
currentIndex?: number;
totalIndex?: number;
percentage: number;
currentIndex?: number;
totalIndex?: number;
}) => void;
/**
* Fetch blocks from web3 provider on batches
*/
export class BatchBlockService {
provider: Provider;
onProgress?: BatchBlockOnProgress;
concurrencySize: number;
batchSize: number;
shouldRetry: boolean;
retryMax: number;
retryOn: number;
constructor({
provider,
onProgress,
concurrencySize = 10,
batchSize = 10,
shouldRetry = true,
retryMax = 5,
retryOn = 500,
}: BatchBlockServiceConstructor) {
this.provider = provider;
this.onProgress = onProgress;
this.concurrencySize = concurrencySize;
this.batchSize = batchSize;
this.shouldRetry = shouldRetry;
this.retryMax = retryMax;
this.retryOn = retryOn;
}
async getBlock(blockTag: BlockTag): Promise<Block> {
const blockObject = await this.provider.getBlock(blockTag);
// if the provider returns null (which they have corrupted block data for one of their nodes) throw and retry
if (!blockObject) {
const errMsg = `No block for ${blockTag}`;
throw new Error(errMsg);
provider: Provider;
onProgress?: BatchBlockOnProgress;
concurrencySize: number;
batchSize: number;
shouldRetry: boolean;
retryMax: number;
retryOn: number;
constructor({
provider,
onProgress,
concurrencySize = 10,
batchSize = 10,
shouldRetry = true,
retryMax = 5,
retryOn = 500,
}: BatchBlockServiceConstructor) {
this.provider = provider;
this.onProgress = onProgress;
this.concurrencySize = concurrencySize;
this.batchSize = batchSize;
this.shouldRetry = shouldRetry;
this.retryMax = retryMax;
this.retryOn = retryOn;
}
return blockObject;
}
async getBlock(blockTag: BlockTag): Promise<Block> {
const blockObject = await this.provider.getBlock(blockTag);
createBatchRequest(batchArray: BlockTag[][]): Promise<Block[]>[] {
return batchArray.map(async (blocks: BlockTag[], index: number) => {
// send batch requests on milliseconds to avoid including them on a single batch request
await sleep(20 * index);
return (async () => {
let retries = 0;
let err;
// eslint-disable-next-line no-unmodified-loop-condition
while ((!this.shouldRetry && retries === 0) || (this.shouldRetry && retries < this.retryMax)) {
try {
return await Promise.all(blocks.map((b) => this.getBlock(b)));
} catch (e) {
retries++;
err = e;
// retry on 0.5 seconds
await sleep(this.retryOn);
}
// if the provider returns null (which they have corrupted block data for one of their nodes) throw and retry
if (!blockObject) {
const errMsg = `No block for ${blockTag}`;
throw new Error(errMsg);
}
throw err;
})();
});
}
async getBatchBlocks(blocks: BlockTag[]): Promise<Block[]> {
let blockCount = 0;
const results: Block[] = [];
for (const chunks of chunk(blocks, this.concurrencySize * this.batchSize)) {
const chunksResult = (await Promise.all(this.createBatchRequest(chunk(chunks, this.batchSize)))).flat();
results.push(...chunksResult);
blockCount += chunks.length;
if (typeof this.onProgress === 'function') {
this.onProgress({
percentage: blockCount / blocks.length,
currentIndex: blockCount,
totalIndex: blocks.length,
});
}
return blockObject;
}
return results;
}
createBatchRequest(batchArray: BlockTag[][]): Promise<Block[]>[] {
return batchArray.map(async (blocks: BlockTag[], index: number) => {
// send batch requests on milliseconds to avoid including them on a single batch request
await sleep(40 * index);
return (async () => {
let retries = 0;
let err;
// eslint-disable-next-line no-unmodified-loop-condition
while ((!this.shouldRetry && retries === 0) || (this.shouldRetry && retries < this.retryMax)) {
try {
return await Promise.all(blocks.map((b) => this.getBlock(b)));
} catch (e) {
retries++;
err = e;
// retry on 0.5 seconds
await sleep(this.retryOn);
}
}
throw err;
})();
});
}
async getBatchBlocks(blocks: BlockTag[]): Promise<Block[]> {
let blockCount = 0;
const results: Block[] = [];
for (const chunks of chunk(blocks, this.concurrencySize * this.batchSize)) {
const chunksResult = (await Promise.all(this.createBatchRequest(chunk(chunks, this.batchSize)))).flat();
results.push(...chunksResult);
blockCount += chunks.length;
if (typeof this.onProgress === 'function') {
this.onProgress({
percentage: blockCount / blocks.length,
currentIndex: blockCount,
totalIndex: blocks.length,
});
}
}
return results;
}
}
/**
* Fetch transactions from web3 provider on batches
*/
export class BatchTransactionService {
provider: Provider;
onProgress?: BatchBlockOnProgress;
concurrencySize: number;
batchSize: number;
shouldRetry: boolean;
retryMax: number;
retryOn: number;
constructor({
provider,
onProgress,
concurrencySize = 10,
batchSize = 10,
shouldRetry = true,
retryMax = 5,
retryOn = 500,
}: BatchBlockServiceConstructor) {
this.provider = provider;
this.onProgress = onProgress;
this.concurrencySize = concurrencySize;
this.batchSize = batchSize;
this.shouldRetry = shouldRetry;
this.retryMax = retryMax;
this.retryOn = retryOn;
}
async getTransaction(txHash: string): Promise<TransactionResponse> {
const txObject = await this.provider.getTransaction(txHash);
if (!txObject) {
const errMsg = `No transaction for ${txHash}`;
throw new Error(errMsg);
provider: Provider;
onProgress?: BatchBlockOnProgress;
concurrencySize: number;
batchSize: number;
shouldRetry: boolean;
retryMax: number;
retryOn: number;
constructor({
provider,
onProgress,
concurrencySize = 10,
batchSize = 10,
shouldRetry = true,
retryMax = 5,
retryOn = 500,
}: BatchBlockServiceConstructor) {
this.provider = provider;
this.onProgress = onProgress;
this.concurrencySize = concurrencySize;
this.batchSize = batchSize;
this.shouldRetry = shouldRetry;
this.retryMax = retryMax;
this.retryOn = retryOn;
}
return txObject;
}
async getTransaction(txHash: string): Promise<TransactionResponse> {
const txObject = await this.provider.getTransaction(txHash);
createBatchRequest(batchArray: string[][]): Promise<TransactionResponse[]>[] {
return batchArray.map(async (txs: string[], index: number) => {
await sleep(20 * index);
return (async () => {
let retries = 0;
let err;
// eslint-disable-next-line no-unmodified-loop-condition
while ((!this.shouldRetry && retries === 0) || (this.shouldRetry && retries < this.retryMax)) {
try {
return await Promise.all(txs.map((tx) => this.getTransaction(tx)));
} catch (e) {
retries++;
err = e;
// retry on 0.5 seconds
await sleep(this.retryOn);
}
if (!txObject) {
const errMsg = `No transaction for ${txHash}`;
throw new Error(errMsg);
}
throw err;
})();
});
}
async getBatchTransactions(txs: string[]): Promise<TransactionResponse[]> {
let txCount = 0;
const results = [];
for (const chunks of chunk(txs, this.concurrencySize * this.batchSize)) {
const chunksResult = (await Promise.all(this.createBatchRequest(chunk(chunks, this.batchSize)))).flat();
results.push(...chunksResult);
txCount += chunks.length;
if (typeof this.onProgress === 'function') {
this.onProgress({ percentage: txCount / txs.length, currentIndex: txCount, totalIndex: txs.length });
}
return txObject;
}
return results;
}
async getTransactionReceipt(txHash: string): Promise<TransactionReceipt> {
const txObject = await this.provider.getTransactionReceipt(txHash);
if (!txObject) {
const errMsg = `No transaction receipt for ${txHash}`;
throw new Error(errMsg);
}
return txObject;
}
createBatchRequest(
batchArray: string[][],
receipt?: boolean,
): Promise<TransactionResponse[] | TransactionReceipt[]>[] {
return batchArray.map(async (txs: string[], index: number) => {
await sleep(40 * index);
return (async () => {
let retries = 0;
let err;
// eslint-disable-next-line no-unmodified-loop-condition
while ((!this.shouldRetry && retries === 0) || (this.shouldRetry && retries < this.retryMax)) {
try {
if (!receipt) {
return await Promise.all(txs.map((tx) => this.getTransaction(tx)));
} else {
return await Promise.all(txs.map((tx) => this.getTransactionReceipt(tx)));
}
} catch (e) {
retries++;
err = e;
// retry on 0.5 seconds
await sleep(this.retryOn);
}
}
throw err;
})();
});
}
async getBatchTransactions(txs: string[]): Promise<TransactionResponse[]> {
let txCount = 0;
const results = [];
for (const chunks of chunk(txs, this.concurrencySize * this.batchSize)) {
const chunksResult = (
await Promise.all(this.createBatchRequest(chunk(chunks, this.batchSize)))
).flat() as TransactionResponse[];
results.push(...chunksResult);
txCount += chunks.length;
if (typeof this.onProgress === 'function') {
this.onProgress({
percentage: txCount / txs.length,
currentIndex: txCount,
totalIndex: txs.length,
});
}
}
return results;
}
async getBatchReceipt(txs: string[]): Promise<TransactionReceipt[]> {
let txCount = 0;
const results = [];
for (const chunks of chunk(txs, this.concurrencySize * this.batchSize)) {
const chunksResult = (
await Promise.all(this.createBatchRequest(chunk(chunks, this.batchSize), true))
).flat() as TransactionReceipt[];
results.push(...chunksResult);
txCount += chunks.length;
if (typeof this.onProgress === 'function') {
this.onProgress({
percentage: txCount / txs.length,
currentIndex: txCount,
totalIndex: txs.length,
});
}
}
return results;
}
}
export interface BatchEventServiceConstructor {
provider: Provider;
contract: BaseContract;
onProgress?: BatchEventOnProgress;
concurrencySize?: number;
blocksPerRequest?: number;
shouldRetry?: boolean;
retryMax?: number;
retryOn?: number;
provider: Provider;
contract: BaseContract;
address?: string | string[];
onProgress?: BatchEventOnProgress;
concurrencySize?: number;
blocksPerRequest?: number;
shouldRetry?: boolean;
retryMax?: number;
retryOn?: number;
}
export type BatchEventOnProgress = ({
percentage,
type,
fromBlock,
toBlock,
count,
percentage,
type,
fromBlock,
toBlock,
count,
}: {
percentage: number;
type?: ContractEventName;
fromBlock?: number;
toBlock?: number;
count?: number;
percentage: number;
type?: ContractEventName;
fromBlock?: number;
toBlock?: number;
count?: number;
}) => void;
// To enable iteration only numbers are accepted for fromBlock input
export type EventInput = {
fromBlock: number;
toBlock: number;
type: ContractEventName;
};
export interface EventInput {
fromBlock: number;
toBlock: number;
type: ContractEventName;
}
/**
* Fetch events from web3 provider on bulk
*/
export class BatchEventsService {
provider: Provider;
contract: BaseContract;
onProgress?: BatchEventOnProgress;
concurrencySize: number;
blocksPerRequest: number;
shouldRetry: boolean;
retryMax: number;
retryOn: number;
constructor({
provider,
contract,
onProgress,
concurrencySize = 10,
blocksPerRequest = 2000,
shouldRetry = true,
retryMax = 5,
retryOn = 500,
}: BatchEventServiceConstructor) {
this.provider = provider;
this.contract = contract;
this.onProgress = onProgress;
this.concurrencySize = concurrencySize;
this.blocksPerRequest = blocksPerRequest;
this.shouldRetry = shouldRetry;
this.retryMax = retryMax;
this.retryOn = retryOn;
}
provider: Provider;
contract: BaseContract;
address?: string | string[];
onProgress?: BatchEventOnProgress;
concurrencySize: number;
blocksPerRequest: number;
shouldRetry: boolean;
retryMax: number;
retryOn: number;
constructor({
provider,
contract,
address,
onProgress,
concurrencySize = 10,
blocksPerRequest = 5000,
shouldRetry = true,
retryMax = 5,
retryOn = 500,
}: BatchEventServiceConstructor) {
this.provider = provider;
this.contract = contract;
this.address = address;
this.onProgress = onProgress;
this.concurrencySize = concurrencySize;
this.blocksPerRequest = blocksPerRequest;
this.shouldRetry = shouldRetry;
this.retryMax = retryMax;
this.retryOn = retryOn;
}
async getPastEvents({ fromBlock, toBlock, type }: EventInput): Promise<EventLog[]> {
let err;
let retries = 0;
async getPastEvents({ fromBlock, toBlock, type }: EventInput): Promise<EventLog[]> {
let err;
let retries = 0;
// eslint-disable-next-line no-unmodified-loop-condition
while ((!this.shouldRetry && retries === 0) || (this.shouldRetry && retries < this.retryMax)) {
try {
return (await this.contract.queryFilter(type, fromBlock, toBlock)) as EventLog[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (e: any) {
err = e;
retries++;
// eslint-disable-next-line no-unmodified-loop-condition
while ((!this.shouldRetry && retries === 0) || (this.shouldRetry && retries < this.retryMax)) {
try {
if (this.address) {
return (await multiQueryFilter(
this.address,
this.contract,
type,
fromBlock,
toBlock,
)) as EventLog[];
}
return (await this.contract.queryFilter(type, fromBlock, toBlock)) as EventLog[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (e: any) {
err = e;
retries++;
// If provider.getBlockNumber returned last block that isn't accepted (happened on Avalanche/Gnosis),
// get events to last accepted block
if (e.message.includes('after last accepted block')) {
const acceptedBlock = parseInt(e.message.split('after last accepted block ')[1]);
toBlock = acceptedBlock;
// If provider.getBlockNumber returned last block that isn't accepted (happened on Avalanche/Gnosis),
// get events to last accepted block
if (e.message.includes('after last accepted block')) {
const acceptedBlock = parseInt(e.message.split('after last accepted block ')[1]);
toBlock = acceptedBlock;
}
// retry on 0.5 seconds
await sleep(this.retryOn);
}
}
// retry on 0.5 seconds
await sleep(this.retryOn);
}
throw err;
}
throw err;
}
createBatchRequest(batchArray: EventInput[]): Promise<EventLog[]>[] {
return batchArray.map(async (event: EventInput, index: number) => {
await sleep(10 * index);
createBatchRequest(batchArray: EventInput[]): Promise<EventLog[]>[] {
return batchArray.map(async (event: EventInput, index: number) => {
await sleep(20 * index);
return this.getPastEvents(event);
});
}
async getBatchEvents({ fromBlock, toBlock, type = '*' }: EventInput): Promise<EventLog[]> {
if (!toBlock) {
toBlock = await this.provider.getBlockNumber();
}
const eventsToSync = [];
for (let i = fromBlock; i < toBlock; i += this.blocksPerRequest) {
const j = i + this.blocksPerRequest - 1 > toBlock ? toBlock : i + this.blocksPerRequest - 1;
eventsToSync.push({ fromBlock: i, toBlock: j, type });
}
const events = [];
const eventChunk = chunk(eventsToSync, this.concurrencySize);
let chunkCount = 0;
for (const chunk of eventChunk) {
chunkCount++;
const fetchedEvents = (await Promise.all(this.createBatchRequest(chunk))).flat();
events.push(...fetchedEvents);
if (typeof this.onProgress === 'function') {
this.onProgress({
percentage: chunkCount / eventChunk.length,
type,
fromBlock: chunk[0].fromBlock,
toBlock: chunk[chunk.length - 1].toBlock,
count: fetchedEvents.length,
return this.getPastEvents(event);
});
}
}
return events;
}
async getBatchEvents({ fromBlock, toBlock, type = '*' }: EventInput): Promise<EventLog[]> {
if (!toBlock) {
toBlock = await this.provider.getBlockNumber();
}
const eventsToSync = [];
for (let i = fromBlock; i < toBlock; i += this.blocksPerRequest) {
const j = i + this.blocksPerRequest - 1 > toBlock ? toBlock : i + this.blocksPerRequest - 1;
eventsToSync.push({ fromBlock: i, toBlock: j, type });
}
const events = [];
const eventChunk = chunk(eventsToSync, this.concurrencySize);
let chunkCount = 0;
for (const chunk of eventChunk) {
chunkCount++;
const fetchedEvents = (await Promise.all(this.createBatchRequest(chunk))).flat();
events.push(...fetchedEvents);
if (typeof this.onProgress === 'function') {
this.onProgress({
percentage: chunkCount / eventChunk.length,
type,
fromBlock: chunk[0].fromBlock,
toBlock: chunk[chunk.length - 1].toBlock,
count: fetchedEvents.length,
});
}
}
return events;
}
}

17
src/contracts.ts Normal file
View File

@@ -0,0 +1,17 @@
export * from '@tornado/contracts';
export {
Multicall,
Multicall__factory,
OffchainOracle,
OffchainOracle__factory,
OvmGasPriceOracle,
OvmGasPriceOracle__factory,
ReverseRecords,
ReverseRecords__factory,
ENSNameWrapper,
ENSNameWrapper__factory,
ENSRegistry,
ENSRegistry__factory,
ENSResolver,
ENSResolver__factory,
} from './typechain';

View File

@@ -2,246 +2,271 @@ import { bnToBytes, bytesToBN, leBuff2Int, leInt2Buff, rBigInt, toFixedHex } fro
import { buffPedersenHash } from './pedersen';
import type { NetIdType } from './networkConfig';
export type DepositType = {
currency: string;
amount: string;
netId: NetIdType;
};
export interface DepositType {
currency: string;
amount: string;
netId: NetIdType;
}
export type createDepositParams = {
nullifier: bigint;
secret: bigint;
};
export interface createDepositParams {
nullifier: bigint;
secret: bigint;
}
export type createDepositObject = {
preimage: Uint8Array;
noteHex: string;
commitment: bigint;
commitmentHex: string;
nullifierHash: bigint;
nullifierHex: string;
};
export interface createDepositObject {
preimage: Uint8Array;
noteHex: string;
commitment: bigint;
commitmentHex: string;
nullifierHash: bigint;
nullifierHex: string;
}
export type createNoteParams = DepositType & {
nullifier?: bigint;
secret?: bigint;
};
export interface createNoteParams extends DepositType {
nullifier?: bigint;
secret?: bigint;
}
export type parsedNoteExec = DepositType & {
note: string;
};
export interface parsedNoteExec extends DepositType {
note: string;
noteHex: string;
}
export type depositTx = {
from: string;
transactionHash: string;
};
export interface parsedInvoiceExec extends DepositType {
invoice: string;
commitmentHex: string;
}
export type withdrawalTx = {
to: string;
transactionHash: string;
};
export function parseNote(noteString: string): parsedNoteExec | undefined {
const noteRegex = /tornado-(?<currency>\w+)-(?<amount>[\d.]+)-(?<netId>\d+)-0x(?<noteHex>[0-9a-fA-F]{124})/g;
const match = noteRegex.exec(noteString);
if (!match) {
return;
}
const { currency, amount, netId, noteHex } = match.groups as unknown as parsedNoteExec;
return {
currency: currency.toLowerCase(),
amount,
netId: Number(netId),
noteHex: '0x' + noteHex,
note: noteString,
};
}
export function parseInvoice(invoiceString: string): parsedInvoiceExec | undefined {
const invoiceRegex =
/tornadoInvoice-(?<currency>\w+)-(?<amount>[\d.]+)-(?<netId>\d+)-0x(?<commitmentHex>[0-9a-fA-F]{64})/g;
const match = invoiceRegex.exec(invoiceString);
if (!match) {
return;
}
const { currency, amount, netId, commitmentHex } = match.groups as unknown as parsedInvoiceExec;
return {
currency: currency.toLowerCase(),
amount,
netId: Number(netId),
commitmentHex: '0x' + commitmentHex,
invoice: invoiceString,
};
}
export async function createDeposit({ nullifier, secret }: createDepositParams): Promise<createDepositObject> {
const preimage = new Uint8Array([...leInt2Buff(nullifier), ...leInt2Buff(secret)]);
const noteHex = toFixedHex(bytesToBN(preimage), 62);
const commitment = BigInt(await buffPedersenHash(preimage));
const commitmentHex = toFixedHex(commitment);
const nullifierHash = BigInt(await buffPedersenHash(leInt2Buff(nullifier)));
const nullifierHex = toFixedHex(nullifierHash);
const preimage = new Uint8Array([...leInt2Buff(nullifier), ...leInt2Buff(secret)]);
const noteHex = toFixedHex(bytesToBN(preimage), 62);
const commitment = BigInt(await buffPedersenHash(preimage));
const commitmentHex = toFixedHex(commitment);
const nullifierHash = BigInt(await buffPedersenHash(leInt2Buff(nullifier)));
const nullifierHex = toFixedHex(nullifierHash);
return {
preimage,
noteHex,
commitment,
commitmentHex,
nullifierHash,
nullifierHex,
};
return {
preimage,
noteHex,
commitment,
commitmentHex,
nullifierHash,
nullifierHex,
};
}
export interface DepositConstructor {
currency: string;
amount: string;
netId: NetIdType;
nullifier: bigint;
secret: bigint;
note: string;
noteHex: string;
invoice: string;
commitmentHex: string;
nullifierHex: string;
currency: string;
amount: string;
netId: NetIdType;
nullifier: bigint;
secret: bigint;
note: string;
noteHex: string;
invoice: string;
commitmentHex: string;
nullifierHex: string;
}
export class Deposit {
currency: string;
amount: string;
netId: NetIdType;
currency: string;
amount: string;
netId: NetIdType;
nullifier: bigint;
secret: bigint;
nullifier: bigint;
secret: bigint;
note: string;
noteHex: string;
invoice: string;
note: string;
noteHex: string;
invoice: string;
commitmentHex: string;
nullifierHex: string;
commitmentHex: string;
nullifierHex: string;
constructor({
currency,
amount,
netId,
nullifier,
secret,
note,
noteHex,
invoice,
commitmentHex,
nullifierHex,
}: DepositConstructor) {
this.currency = currency;
this.amount = amount;
this.netId = netId;
constructor({
currency,
amount,
netId,
nullifier,
secret,
note,
noteHex,
invoice,
commitmentHex,
nullifierHex,
}: DepositConstructor) {
this.currency = currency;
this.amount = amount;
this.netId = netId;
this.nullifier = nullifier;
this.secret = secret;
this.nullifier = nullifier;
this.secret = secret;
this.note = note;
this.noteHex = noteHex;
this.invoice = invoice;
this.note = note;
this.noteHex = noteHex;
this.invoice = invoice;
this.commitmentHex = commitmentHex;
this.nullifierHex = nullifierHex;
}
toString() {
return JSON.stringify(
{
currency: this.currency,
amount: this.amount,
netId: this.netId,
nullifier: this.nullifier,
secret: this.secret,
note: this.note,
noteHex: this.noteHex,
invoice: this.invoice,
commitmentHex: this.commitmentHex,
nullifierHex: this.nullifierHex,
},
null,
2,
);
}
static async createNote({ currency, amount, netId, nullifier, secret }: createNoteParams): Promise<Deposit> {
if (!nullifier) {
nullifier = rBigInt(31);
}
if (!secret) {
secret = rBigInt(31);
this.commitmentHex = commitmentHex;
this.nullifierHex = nullifierHex;
}
const depositObject = await createDeposit({
nullifier,
secret,
});
const newDeposit = new Deposit({
currency: currency.toLowerCase(),
amount: amount,
netId,
note: `tornado-${currency.toLowerCase()}-${amount}-${netId}-${depositObject.noteHex}`,
noteHex: depositObject.noteHex,
invoice: `tornadoInvoice-${currency.toLowerCase()}-${amount}-${netId}-${depositObject.commitmentHex}`,
nullifier: nullifier,
secret: secret,
commitmentHex: depositObject.commitmentHex,
nullifierHex: depositObject.nullifierHex,
});
return newDeposit;
}
static async parseNote(noteString: string): Promise<Deposit> {
const noteRegex = /tornado-(?<currency>\w+)-(?<amount>[\d.]+)-(?<netId>\d+)-0x(?<note>[0-9a-fA-F]{124})/g;
const match = noteRegex.exec(noteString);
if (!match) {
throw new Error('The note has invalid format');
toString() {
return JSON.stringify(
{
currency: this.currency,
amount: this.amount,
netId: this.netId,
nullifier: this.nullifier,
secret: this.secret,
note: this.note,
noteHex: this.noteHex,
invoice: this.invoice,
commitmentHex: this.commitmentHex,
nullifierHex: this.nullifierHex,
},
null,
2,
);
}
const matchGroup = match?.groups as unknown as parsedNoteExec;
const currency = matchGroup.currency.toLowerCase();
const amount = matchGroup.amount;
const netId = Number(matchGroup.netId);
static async createNote({ currency, amount, netId, nullifier, secret }: createNoteParams): Promise<Deposit> {
if (!nullifier) {
nullifier = rBigInt(31);
}
if (!secret) {
secret = rBigInt(31);
}
const bytes = bnToBytes('0x' + matchGroup.note);
const nullifier = BigInt(leBuff2Int(bytes.slice(0, 31)).toString());
const secret = BigInt(leBuff2Int(bytes.slice(31, 62)).toString());
const depositObject = await createDeposit({
nullifier,
secret,
});
const depositObject = await createDeposit({ nullifier, secret });
const newDeposit = new Deposit({
currency: currency.toLowerCase(),
amount: amount,
netId,
note: `tornado-${currency.toLowerCase()}-${amount}-${netId}-${depositObject.noteHex}`,
noteHex: depositObject.noteHex,
invoice: `tornadoInvoice-${currency.toLowerCase()}-${amount}-${netId}-${depositObject.commitmentHex}`,
nullifier: nullifier,
secret: secret,
commitmentHex: depositObject.commitmentHex,
nullifierHex: depositObject.nullifierHex,
});
const invoice = `tornadoInvoice-${currency}-${amount}-${netId}-${depositObject.commitmentHex}`;
return newDeposit;
}
const newDeposit = new Deposit({
currency,
amount,
netId,
note: noteString,
noteHex: depositObject.noteHex,
invoice,
nullifier,
secret,
commitmentHex: depositObject.commitmentHex,
nullifierHex: depositObject.nullifierHex,
});
static async parseNote(noteString: string): Promise<Deposit> {
const parsedNote = parseNote(noteString);
return newDeposit;
}
if (!parsedNote) {
throw new Error('The note has invalid format');
}
const { currency, amount, netId, note, noteHex: parsedNoteHex } = parsedNote;
const bytes = bnToBytes(parsedNoteHex);
const nullifier = BigInt(leBuff2Int(bytes.slice(0, 31)).toString());
const secret = BigInt(leBuff2Int(bytes.slice(31, 62)).toString());
const { noteHex, commitmentHex, nullifierHex } = await createDeposit({
nullifier,
secret,
});
const invoice = `tornadoInvoice-${currency}-${amount}-${netId}-${commitmentHex}`;
const newDeposit = new Deposit({
currency,
amount,
netId,
note,
noteHex,
invoice,
nullifier,
secret,
commitmentHex,
nullifierHex,
});
return newDeposit;
}
}
export type parsedInvoiceExec = DepositType & {
commitment: string;
};
export class Invoice {
currency: string;
amount: string;
netId: NetIdType;
commitment: string;
invoice: string;
currency: string;
amount: string;
netId: NetIdType;
commitmentHex: string;
invoice: string;
constructor(invoiceString: string) {
const invoiceRegex =
/tornadoInvoice-(?<currency>\w+)-(?<amount>[\d.]+)-(?<netId>\d+)-0x(?<commitment>[0-9a-fA-F]{64})/g;
const match = invoiceRegex.exec(invoiceString);
if (!match) {
throw new Error('The note has invalid format');
constructor(invoiceString: string) {
const parsedInvoice = parseInvoice(invoiceString);
if (!parsedInvoice) {
throw new Error('The invoice has invalid format');
}
const { currency, amount, netId, invoice, commitmentHex } = parsedInvoice;
this.currency = currency;
this.amount = amount;
this.netId = netId;
this.commitmentHex = commitmentHex;
this.invoice = invoice;
}
const matchGroup = match?.groups as unknown as parsedInvoiceExec;
const currency = matchGroup.currency.toLowerCase();
const amount = matchGroup.amount;
const netId = Number(matchGroup.netId);
this.currency = currency;
this.amount = amount;
this.netId = netId;
this.commitment = '0x' + matchGroup.commitment;
this.invoice = invoiceString;
}
toString() {
return JSON.stringify(
{
currency: this.currency,
amount: this.amount,
netId: this.netId,
commitment: this.commitment,
invoice: this.invoice,
},
null,
2,
);
}
toString() {
return JSON.stringify(
{
currency: this.currency,
amount: this.amount,
netId: this.netId,
commitmentHex: this.commitmentHex,
invoice: this.invoice,
},
null,
2,
);
}
}

View File

@@ -1,189 +1,209 @@
import { getEncryptionPublicKey, encrypt, decrypt, EthEncryptedData } from '@metamask/eth-sig-util';
import { Echoer } from '@tornado/contracts';
import { Wallet, computeAddress, getAddress } from 'ethers';
import { crypto, base64ToBytes, bytesToBase64, bytesToHex, hexToBytes, toFixedHex, concatBytes } from './utils';
import { JsonRpcApiProvider, Signer, Wallet, computeAddress, getAddress } from 'ethers';
import { base64ToBytes, bytesToBase64, bytesToHex, hexToBytes, toFixedHex, concatBytes, rHex } from './utils';
import { EchoEvents, EncryptedNotesEvents } from './events';
import type { NetIdType } from './networkConfig';
export interface NoteToEncrypt {
address: string;
noteHex: string;
address: string;
noteHex: string;
}
export interface DecryptedNotes {
blockNumber: number;
address: string;
noteHex: string;
blockNumber: number;
address: string;
noteHex: string;
}
export function packEncryptedMessage({ nonce, ephemPublicKey, ciphertext }: EthEncryptedData) {
const nonceBuf = toFixedHex(bytesToHex(base64ToBytes(nonce)), 24);
const ephemPublicKeyBuf = toFixedHex(bytesToHex(base64ToBytes(ephemPublicKey)), 32);
const ciphertextBuf = bytesToHex(base64ToBytes(ciphertext));
const nonceBuf = toFixedHex(bytesToHex(base64ToBytes(nonce)), 24);
const ephemPublicKeyBuf = toFixedHex(bytesToHex(base64ToBytes(ephemPublicKey)), 32);
const ciphertextBuf = bytesToHex(base64ToBytes(ciphertext));
const messageBuff = concatBytes(hexToBytes(nonceBuf), hexToBytes(ephemPublicKeyBuf), hexToBytes(ciphertextBuf));
const messageBuff = concatBytes(hexToBytes(nonceBuf), hexToBytes(ephemPublicKeyBuf), hexToBytes(ciphertextBuf));
return bytesToHex(messageBuff);
return bytesToHex(messageBuff);
}
export function unpackEncryptedMessage(encryptedMessage: string) {
const messageBuff = hexToBytes(encryptedMessage);
const nonceBuf = bytesToBase64(messageBuff.slice(0, 24));
const ephemPublicKeyBuf = bytesToBase64(messageBuff.slice(24, 56));
const ciphertextBuf = bytesToBase64(messageBuff.slice(56));
const messageBuff = hexToBytes(encryptedMessage);
const nonceBuf = bytesToBase64(messageBuff.slice(0, 24));
const ephemPublicKeyBuf = bytesToBase64(messageBuff.slice(24, 56));
const ciphertextBuf = bytesToBase64(messageBuff.slice(56));
return {
messageBuff: bytesToHex(messageBuff),
version: 'x25519-xsalsa20-poly1305',
nonce: nonceBuf,
ephemPublicKey: ephemPublicKeyBuf,
ciphertext: ciphertextBuf,
} as EthEncryptedData & {
messageBuff: string;
};
return {
messageBuff: bytesToHex(messageBuff),
version: 'x25519-xsalsa20-poly1305',
nonce: nonceBuf,
ephemPublicKey: ephemPublicKeyBuf,
ciphertext: ciphertextBuf,
} as EthEncryptedData & {
messageBuff: string;
};
}
export interface NoteAccountConstructor {
netId: NetIdType;
blockNumber?: number;
// hex
recoveryKey?: string;
Echoer: Echoer;
blockNumber?: number;
// hex
recoveryKey?: string;
}
export class NoteAccount {
netId: NetIdType;
blockNumber?: number;
// Dedicated 32 bytes private key only used for note encryption, backed up to an Echoer and local for future derivation
// Note that unlike the private key it shouldn't have the 0x prefix
recoveryKey: string;
// Address derived from recoveryKey, only used for frontend UI
recoveryAddress: string;
// Note encryption public key derived from recoveryKey
recoveryPublicKey: string;
Echoer: Echoer;
blockNumber?: number;
// Dedicated 32 bytes private key only used for note encryption, backed up to an Echoer and local for future derivation
// Note that unlike the private key it shouldn't have the 0x prefix
recoveryKey: string;
// Address derived from recoveryKey, only used for frontend UI
recoveryAddress: string;
// Note encryption public key derived from recoveryKey
recoveryPublicKey: string;
constructor({ netId, blockNumber, recoveryKey, Echoer }: NoteAccountConstructor) {
if (!recoveryKey) {
recoveryKey = bytesToHex(crypto.getRandomValues(new Uint8Array(32))).slice(2);
constructor({ blockNumber, recoveryKey }: NoteAccountConstructor) {
if (!recoveryKey) {
recoveryKey = rHex(32).slice(2);
}
this.blockNumber = blockNumber;
this.recoveryKey = recoveryKey;
this.recoveryAddress = computeAddress('0x' + recoveryKey);
this.recoveryPublicKey = getEncryptionPublicKey(recoveryKey);
}
this.netId = Math.floor(Number(netId));
this.blockNumber = blockNumber;
this.recoveryKey = recoveryKey;
this.recoveryAddress = computeAddress('0x' + recoveryKey);
this.recoveryPublicKey = getEncryptionPublicKey(recoveryKey);
this.Echoer = Echoer;
}
/**
* Intends to mock eth_getEncryptionPublicKey behavior from MetaMask
* In order to make the recoveryKey retrival from Echoer possible from the bare private key
*/
static async getSignerPublicKey(signer: Signer | Wallet) {
if ((signer as Wallet).privateKey) {
const wallet = signer as Wallet;
const privateKey = wallet.privateKey.slice(0, 2) === '0x' ? wallet.privateKey.slice(2) : wallet.privateKey;
/**
* Intends to mock eth_getEncryptionPublicKey behavior from MetaMask
* In order to make the recoveryKey retrival from Echoer possible from the bare private key
*/
static getWalletPublicKey(wallet: Wallet) {
let { privateKey } = wallet;
// Should return base64 encoded public key
return getEncryptionPublicKey(privateKey);
}
if (privateKey.startsWith('0x')) {
privateKey = privateKey.replace('0x', '');
const provider = signer.provider as JsonRpcApiProvider;
return (await provider.send('eth_getEncryptionPublicKey', [
(signer as Signer & { address: string }).address,
])) as string;
}
// Should return base64 encoded public key
return getEncryptionPublicKey(privateKey);
}
// This function intends to provide an encrypted value of recoveryKey for an on-chain Echoer backup purpose
// Thus, the pubKey should be derived by a Wallet instance or from Web3 wallets
// pubKey: base64 encoded 32 bytes key from https://docs.metamask.io/wallet/reference/eth_getencryptionpublickey/
getEncryptedAccount(walletPublicKey: string) {
const encryptedData = encrypt({
publicKey: walletPublicKey,
data: this.recoveryKey,
version: 'x25519-xsalsa20-poly1305',
});
const data = packEncryptedMessage(encryptedData);
return {
// Use this later to save hexPrivateKey generated with
// Buffer.from(JSON.stringify(encryptedData)).toString('hex')
// As we don't use buffer with this library we should leave UI to do the rest
encryptedData,
// Data that could be used as an echo(data) params
data,
};
}
/**
* Decrypt Echoer backuped note encryption account with private keys
*/
decryptAccountsWithWallet(wallet: Wallet, events: EchoEvents[]): NoteAccount[] {
let { privateKey } = wallet;
if (privateKey.startsWith('0x')) {
privateKey = privateKey.replace('0x', '');
}
const decryptedEvents = [];
for (const event of events) {
try {
const unpackedMessage = unpackEncryptedMessage(event.encryptedAccount);
const recoveryKey = decrypt({
encryptedData: unpackedMessage,
privateKey,
// This function intends to provide an encrypted value of recoveryKey for an on-chain Echoer backup purpose
// Thus, the pubKey should be derived by a Wallet instance or from Web3 wallets
// pubKey: base64 encoded 32 bytes key from https://docs.metamask.io/wallet/reference/eth_getencryptionpublickey/
getEncryptedAccount(walletPublicKey: string) {
const encryptedData = encrypt({
publicKey: walletPublicKey,
data: this.recoveryKey,
version: 'x25519-xsalsa20-poly1305',
});
decryptedEvents.push(
new NoteAccount({
netId: this.netId,
blockNumber: event.blockNumber,
recoveryKey,
Echoer: this.Echoer,
}),
);
} catch {
// decryption may fail for invalid accounts
continue;
}
const data = packEncryptedMessage(encryptedData);
return {
// Use this later to save hexPrivateKey generated with
// Buffer.from(JSON.stringify(encryptedData)).toString('hex')
// As we don't use buffer with this library we should leave UI to do the rest
encryptedData,
// Data that could be used as an echo(data) params
data,
};
}
return decryptedEvents;
}
/**
* Decrypt Echoer backuped note encryption account with private keys
*/
static async decryptSignerNoteAccounts(signer: Signer | Wallet, events: EchoEvents[]): Promise<NoteAccount[]> {
const signerAddress = (signer as (Signer & { address: string }) | Wallet).address;
decryptNotes(events: EncryptedNotesEvents[]): DecryptedNotes[] {
const decryptedEvents = [];
const decryptedEvents = [];
for (const event of events) {
try {
const unpackedMessage = unpackEncryptedMessage(event.encryptedNote);
for (const event of events) {
if (event.address !== signerAddress) {
continue;
}
const [address, noteHex] = decrypt({
encryptedData: unpackedMessage,
privateKey: this.recoveryKey,
}).split('-');
try {
const unpackedMessage = unpackEncryptedMessage(event.encryptedAccount);
decryptedEvents.push({
blockNumber: event.blockNumber,
address: getAddress(address),
noteHex,
let recoveryKey;
if ((signer as Wallet).privateKey) {
const wallet = signer as Wallet;
const privateKey =
wallet.privateKey.slice(0, 2) === '0x' ? wallet.privateKey.slice(2) : wallet.privateKey;
recoveryKey = decrypt({
encryptedData: unpackedMessage,
privateKey,
});
} else {
const { version, nonce, ephemPublicKey, ciphertext } = unpackedMessage;
const unpackedBuffer = bytesToHex(
new TextEncoder().encode(
JSON.stringify({
version,
nonce,
ephemPublicKey,
ciphertext,
}),
),
);
const provider = signer.provider as JsonRpcApiProvider;
recoveryKey = await provider.send('eth_decrypt', [unpackedBuffer, signerAddress]);
}
decryptedEvents.push(
new NoteAccount({
blockNumber: event.blockNumber,
recoveryKey,
}),
);
} catch {
// decryption may fail for invalid accounts
continue;
}
}
return decryptedEvents;
}
decryptNotes(events: EncryptedNotesEvents[]): DecryptedNotes[] {
const decryptedEvents = [];
for (const event of events) {
try {
const unpackedMessage = unpackEncryptedMessage(event.encryptedNote);
const [address, noteHex] = decrypt({
encryptedData: unpackedMessage,
privateKey: this.recoveryKey,
}).split('-');
decryptedEvents.push({
blockNumber: event.blockNumber,
address: getAddress(address),
noteHex,
});
} catch {
// decryption may fail for foreign notes
continue;
}
}
return decryptedEvents;
}
encryptNote({ address, noteHex }: NoteToEncrypt) {
const encryptedData = encrypt({
publicKey: this.recoveryPublicKey,
data: `${address}-${noteHex}`,
version: 'x25519-xsalsa20-poly1305',
});
} catch {
// decryption may fail for foreign notes
continue;
}
return packEncryptedMessage(encryptedData);
}
return decryptedEvents;
}
encryptNote({ address, noteHex }: NoteToEncrypt) {
const encryptedData = encrypt({
publicKey: this.recoveryPublicKey,
data: `${address}-${noteHex}`,
version: 'x25519-xsalsa20-poly1305',
});
return packEncryptedMessage(encryptedData);
}
}

145
src/ens.ts Normal file
View File

@@ -0,0 +1,145 @@
import { namehash, EnsResolver, AbstractProvider, keccak256, Signer } from 'ethers';
import {
ENSNameWrapper,
ENSNameWrapper__factory,
ENSRegistry,
ENSRegistry__factory,
ENSResolver,
ENSResolver__factory,
} from './typechain';
import { bytesToHex, isHex } from './utils';
import { NetId, NetIdType } from './networkConfig';
export function encodedLabelToLabelhash(label: string): string | null {
if (label.length !== 66) return null;
if (label.indexOf('[') !== 0) return null;
if (label.indexOf(']') !== 65) return null;
const hash = `0x${label.slice(1, 65)}`;
if (!isHex(hash)) return null;
return hash;
}
export function labelhash(label: string) {
if (!label) {
return bytesToHex(new Uint8Array(32).fill(0));
}
return encodedLabelToLabelhash(label) || keccak256(new TextEncoder().encode(label));
}
export function makeLabelNodeAndParent(name: string) {
const labels = name.split('.');
const label = labels.shift() as string;
const parentNode = namehash(labels.join('.'));
return {
label,
labelhash: labelhash(label),
parentNode,
};
}
// https://github.com/ensdomains/ensjs/blob/main/packages/ensjs/src/contracts/consts.ts
export const EnsContracts: {
[key: NetIdType]: {
ensRegistry: string;
ensPublicResolver: string;
ensNameWrapper: string;
};
} = {
[NetId.MAINNET]: {
ensRegistry: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e',
ensPublicResolver: '0x231b0Ee14048e9dCcD1d247744d114a4EB5E8E63',
ensNameWrapper: '0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401',
},
[NetId.SEPOLIA]: {
ensRegistry: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e',
ensPublicResolver: '0x8FADE66B79cC9f707aB26799354482EB93a5B7dD',
ensNameWrapper: '0x0635513f179D50A207757E05759CbD106d7dFcE8',
},
};
/**
* ENSUtils to manage on-chain registered relayers
*/
export class ENSUtils {
ENSRegistry?: ENSRegistry;
ENSResolver?: ENSResolver;
ENSNameWrapper?: ENSNameWrapper;
provider: AbstractProvider;
constructor(provider: AbstractProvider) {
this.provider = provider;
}
async getContracts() {
const { chainId } = await this.provider.getNetwork();
const { ensRegistry, ensPublicResolver, ensNameWrapper } = EnsContracts[Number(chainId)];
this.ENSRegistry = ENSRegistry__factory.connect(ensRegistry, this.provider);
this.ENSResolver = ENSResolver__factory.connect(ensPublicResolver, this.provider);
this.ENSNameWrapper = ENSNameWrapper__factory.connect(ensNameWrapper, this.provider);
}
async getOwner(name: string) {
if (!this.ENSRegistry) {
await this.getContracts();
}
return (this.ENSRegistry as ENSRegistry).owner(namehash(name));
}
// nameWrapper connected with wallet signer
async unwrap(signer: Signer, name: string) {
if (!this.ENSNameWrapper) {
await this.getContracts();
}
const owner = (signer as unknown as { address: string }).address;
const nameWrapper = (this.ENSNameWrapper as ENSNameWrapper).connect(signer);
const { labelhash } = makeLabelNodeAndParent(name);
return nameWrapper.unwrapETH2LD(labelhash, owner, owner);
}
// https://github.com/ensdomains/ensjs/blob/main/packages/ensjs/src/functions/wallet/createSubname.ts
async setSubnodeRecord(signer: Signer, name: string) {
if (!this.ENSResolver) {
await this.getContracts();
}
const resolver = this.ENSResolver as ENSResolver;
const registry = (this.ENSRegistry as ENSRegistry).connect(signer);
const owner = (signer as unknown as { address: string }).address;
const { labelhash, parentNode } = makeLabelNodeAndParent(name);
return registry.setSubnodeRecord(parentNode, labelhash, owner, resolver.target, BigInt(0));
}
getResolver(name: string) {
return EnsResolver.fromName(this.provider, name);
}
async getText(name: string, key: string) {
const resolver = await this.getResolver(name);
// Retuns null if the name doesn't exist
if (!resolver) {
return resolver;
}
return (await resolver.getText(key)) || '';
}
// https://github.com/ensdomains/ensjs/blob/main/packages/ensjs/src/functions/wallet/setTextRecord.ts
async setText(signer: Signer, name: string, key: string, value: string) {
const resolver = ENSResolver__factory.connect((await this.getResolver(name))?.address as string, signer);
return resolver.setText(namehash(name), key, value);
}
}

File diff suppressed because it is too large Load Diff

559
src/events/db.ts Normal file
View File

@@ -0,0 +1,559 @@
import { downloadZip } from '../zip';
import { IndexedDB } from '../idb';
import { bytesToBase64, digest } from '../utils';
import { fetchData } from '../providers';
import {
BaseTornadoService,
BaseTornadoServiceConstructor,
BaseEchoService,
BaseEchoServiceConstructor,
BaseEncryptedNotesService,
BaseEncryptedNotesServiceConstructor,
BaseGovernanceService,
BaseGovernanceServiceConstructor,
BaseRegistryService,
BaseRegistryServiceConstructor,
BaseRevenueService,
BaseRevenueServiceConstructor,
CachedRelayers,
BaseMultiTornadoService,
BaseMultiTornadoServiceConstructor,
} from './base';
import {
BaseEvents,
MinimalEvents,
DepositsEvents,
WithdrawalsEvents,
CachedEvents,
EchoEvents,
EncryptedNotesEvents,
AllGovernanceEvents,
AllRelayerRegistryEvents,
StakeBurnedEvents,
MultiDepositsEvents,
MultiWithdrawalsEvents,
} from './types';
export async function saveDBEvents<T extends MinimalEvents>({
idb,
instanceName,
newEvents,
lastBlock,
}: {
idb: IndexedDB;
instanceName: string;
newEvents: T[];
lastBlock: number;
}) {
try {
const formattedEvents = newEvents.map((e) => {
return {
eid: `${e.transactionHash}_${e.logIndex}`,
...e,
};
});
await idb.createMultipleTransactions({
data: formattedEvents,
storeName: instanceName,
});
await idb.putItem({
data: {
blockNumber: lastBlock,
name: instanceName,
},
storeName: 'lastEvents',
});
} catch (err) {
console.log('Method saveDBEvents has error');
console.log(err);
}
}
export async function loadDBEvents<T extends MinimalEvents>({
idb,
instanceName,
}: {
idb: IndexedDB;
instanceName: string;
}): Promise<BaseEvents<T>> {
try {
const lastBlockStore = await idb.getItem<{
blockNumber: number;
name: string;
}>({
storeName: 'lastEvents',
key: instanceName,
});
if (!lastBlockStore?.blockNumber) {
return {
events: [],
lastBlock: 0,
};
}
const events = (
await idb.getAll<(T & { eid?: string })[]>({
storeName: instanceName,
})
).map((e) => {
delete e.eid;
return e;
});
return {
events,
lastBlock: lastBlockStore.blockNumber,
};
} catch (err) {
console.log('Method loadDBEvents has error');
console.log(err);
return {
events: [],
lastBlock: 0,
};
}
}
export async function loadRemoteEvents<T extends MinimalEvents>({
staticUrl,
instanceName,
deployedBlock,
zipDigest,
}: {
staticUrl: string;
instanceName: string;
deployedBlock: number;
zipDigest?: string;
}): Promise<CachedEvents<T>> {
try {
const zipName = `${instanceName}.json`.toLowerCase();
const events = await downloadZip<T[]>({
staticUrl,
zipName,
zipDigest,
});
if (!Array.isArray(events)) {
const errStr = `Invalid events from ${staticUrl}/${zipName}`;
throw new Error(errStr);
}
return {
events,
lastBlock: events[events.length - 1]?.blockNumber || deployedBlock,
fromCache: true,
};
} catch (err) {
console.log('Method loadRemoteEvents has error');
console.log(err);
return {
events: [],
lastBlock: deployedBlock,
fromCache: true,
};
}
}
export interface DBTornadoServiceConstructor extends BaseTornadoServiceConstructor {
staticUrl: string;
idb: IndexedDB;
}
export class DBTornadoService extends BaseTornadoService {
staticUrl: string;
idb: IndexedDB;
zipDigest?: string;
constructor(params: DBTornadoServiceConstructor) {
super(params);
this.staticUrl = params.staticUrl;
this.idb = params.idb;
}
async getEventsFromDB() {
return await loadDBEvents<DepositsEvents | WithdrawalsEvents>({
idb: this.idb,
instanceName: this.getInstanceName(),
});
}
async getEventsFromCache() {
return await loadRemoteEvents<DepositsEvents | WithdrawalsEvents>({
staticUrl: this.staticUrl,
instanceName: this.getInstanceName(),
deployedBlock: this.deployedBlock,
zipDigest: this.zipDigest,
});
}
async saveEvents({
newEvents,
lastBlock,
}: BaseEvents<DepositsEvents | WithdrawalsEvents> & { newEvents: (DepositsEvents | WithdrawalsEvents)[] }) {
await saveDBEvents<DepositsEvents | WithdrawalsEvents>({
idb: this.idb,
instanceName: this.getInstanceName(),
newEvents,
lastBlock,
});
}
}
export interface DBMultiTornadoServiceConstructor extends BaseMultiTornadoServiceConstructor {
staticUrl: string;
idb: IndexedDB;
}
export class DBMultiTornadoService extends BaseMultiTornadoService {
staticUrl: string;
idb: IndexedDB;
zipDigest?: string;
constructor(params: DBMultiTornadoServiceConstructor) {
super(params);
this.staticUrl = params.staticUrl;
this.idb = params.idb;
}
async getEventsFromDB() {
return await loadDBEvents<MultiDepositsEvents | MultiWithdrawalsEvents>({
idb: this.idb,
instanceName: this.getInstanceName(),
});
}
async getEventsFromCache() {
return await loadRemoteEvents<MultiDepositsEvents | MultiWithdrawalsEvents>({
staticUrl: this.staticUrl,
instanceName: this.getInstanceName(),
deployedBlock: this.deployedBlock,
zipDigest: this.zipDigest,
});
}
async saveEvents({
newEvents,
lastBlock,
}: BaseEvents<MultiDepositsEvents | MultiWithdrawalsEvents> & {
newEvents: (MultiDepositsEvents | MultiWithdrawalsEvents)[];
}) {
await saveDBEvents<MultiDepositsEvents | MultiWithdrawalsEvents>({
idb: this.idb,
instanceName: this.getInstanceName(),
newEvents,
lastBlock,
});
}
}
export interface DBEchoServiceConstructor extends BaseEchoServiceConstructor {
staticUrl: string;
idb: IndexedDB;
}
export class DBEchoService extends BaseEchoService {
staticUrl: string;
idb: IndexedDB;
zipDigest?: string;
constructor(params: DBEchoServiceConstructor) {
super(params);
this.staticUrl = params.staticUrl;
this.idb = params.idb;
}
async getEventsFromDB() {
return await loadDBEvents<EchoEvents>({
idb: this.idb,
instanceName: this.getInstanceName(),
});
}
async getEventsFromCache() {
return await loadRemoteEvents<EchoEvents>({
staticUrl: this.staticUrl,
instanceName: this.getInstanceName(),
deployedBlock: this.deployedBlock,
zipDigest: this.zipDigest,
});
}
async saveEvents({ newEvents, lastBlock }: BaseEvents<EchoEvents> & { newEvents: EchoEvents[] }) {
await saveDBEvents<EchoEvents>({
idb: this.idb,
instanceName: this.getInstanceName(),
newEvents,
lastBlock,
});
}
}
export interface DBEncryptedNotesServiceConstructor extends BaseEncryptedNotesServiceConstructor {
staticUrl: string;
idb: IndexedDB;
}
export class DBEncryptedNotesService extends BaseEncryptedNotesService {
staticUrl: string;
idb: IndexedDB;
zipDigest?: string;
constructor(params: DBEncryptedNotesServiceConstructor) {
super(params);
this.staticUrl = params.staticUrl;
this.idb = params.idb;
}
async getEventsFromDB() {
return await loadDBEvents<EncryptedNotesEvents>({
idb: this.idb,
instanceName: this.getInstanceName(),
});
}
async getEventsFromCache() {
return await loadRemoteEvents<EncryptedNotesEvents>({
staticUrl: this.staticUrl,
instanceName: this.getInstanceName(),
deployedBlock: this.deployedBlock,
zipDigest: this.zipDigest,
});
}
async saveEvents({
newEvents,
lastBlock,
}: BaseEvents<EncryptedNotesEvents> & { newEvents: EncryptedNotesEvents[] }) {
await saveDBEvents<EncryptedNotesEvents>({
idb: this.idb,
instanceName: this.getInstanceName(),
newEvents,
lastBlock,
});
}
}
export interface DBGovernanceServiceConstructor extends BaseGovernanceServiceConstructor {
staticUrl: string;
idb: IndexedDB;
}
export class DBGovernanceService extends BaseGovernanceService {
staticUrl: string;
idb: IndexedDB;
zipDigest?: string;
constructor(params: DBGovernanceServiceConstructor) {
super(params);
this.staticUrl = params.staticUrl;
this.idb = params.idb;
}
async getEventsFromDB() {
return await loadDBEvents<AllGovernanceEvents>({
idb: this.idb,
instanceName: this.getInstanceName(),
});
}
async getEventsFromCache() {
return await loadRemoteEvents<AllGovernanceEvents>({
staticUrl: this.staticUrl,
instanceName: this.getInstanceName(),
deployedBlock: this.deployedBlock,
zipDigest: this.zipDigest,
});
}
async saveEvents({ newEvents, lastBlock }: BaseEvents<AllGovernanceEvents> & { newEvents: AllGovernanceEvents[] }) {
await saveDBEvents<AllGovernanceEvents>({
idb: this.idb,
instanceName: this.getInstanceName(),
newEvents,
lastBlock,
});
}
}
export interface DBRegistryServiceConstructor extends BaseRegistryServiceConstructor {
staticUrl: string;
idb: IndexedDB;
}
export class DBRegistryService extends BaseRegistryService {
staticUrl: string;
idb: IndexedDB;
zipDigest?: string;
relayerJsonDigest?: string;
constructor(params: DBRegistryServiceConstructor) {
super(params);
this.staticUrl = params.staticUrl;
this.idb = params.idb;
}
async getEventsFromDB() {
return await loadDBEvents<AllRelayerRegistryEvents>({
idb: this.idb,
instanceName: this.getInstanceName(),
});
}
async getEventsFromCache() {
return await loadRemoteEvents<AllRelayerRegistryEvents>({
staticUrl: this.staticUrl,
instanceName: this.getInstanceName(),
deployedBlock: this.deployedBlock,
zipDigest: this.zipDigest,
});
}
async saveEvents({
newEvents,
lastBlock,
}: BaseEvents<AllRelayerRegistryEvents> & { newEvents: AllRelayerRegistryEvents[] }) {
await saveDBEvents<AllRelayerRegistryEvents>({
idb: this.idb,
instanceName: this.getInstanceName(),
newEvents,
lastBlock,
});
}
async getRelayersFromDB(): Promise<CachedRelayers> {
try {
const allCachedRelayers = await this.idb.getAll<CachedRelayers[]>({
storeName: `relayers_${this.netId}`,
});
if (!allCachedRelayers?.length) {
return {
lastBlock: 0,
timestamp: 0,
relayers: [],
};
}
return allCachedRelayers.slice(-1)[0];
} catch (err) {
console.log('Method getRelayersFromDB has error');
console.log(err);
return {
lastBlock: 0,
timestamp: 0,
relayers: [],
};
}
}
async getRelayersFromCache(): Promise<CachedRelayers> {
const url = `${this.staticUrl}/relayers.json`;
try {
const resp = await fetchData(url, {
method: 'GET',
returnResponse: true,
});
const data = new Uint8Array(await resp.arrayBuffer());
if (this.relayerJsonDigest) {
const hash = 'sha384-' + bytesToBase64(await digest(data));
if (hash !== this.relayerJsonDigest) {
const errMsg = `Invalid digest hash for ${url}, wants ${this.relayerJsonDigest} has ${hash}`;
throw new Error(errMsg);
}
}
return JSON.parse(new TextDecoder().decode(data)) as CachedRelayers;
} catch (err) {
console.log('Method getRelayersFromCache has error');
console.log(err);
return {
lastBlock: 0,
timestamp: 0,
relayers: [],
};
}
}
async saveRelayers(cachedRelayers: CachedRelayers): Promise<void> {
try {
await this.idb.putItem({
data: cachedRelayers,
storeName: `relayers_${this.netId}`,
});
} catch (err) {
console.log('Method saveRelayers has error');
console.log(err);
}
}
}
export interface DBRevenueServiceConstructor extends BaseRevenueServiceConstructor {
staticUrl: string;
idb: IndexedDB;
}
export class DBRevenueService extends BaseRevenueService {
staticUrl: string;
idb: IndexedDB;
zipDigest?: string;
relayerJsonDigest?: string;
constructor(params: DBRevenueServiceConstructor) {
super(params);
this.staticUrl = params.staticUrl;
this.idb = params.idb;
}
async getEventsFromDB() {
return await loadDBEvents<StakeBurnedEvents>({
idb: this.idb,
instanceName: this.getInstanceName(),
});
}
async getEventsFromCache() {
return await loadRemoteEvents<StakeBurnedEvents>({
staticUrl: this.staticUrl,
instanceName: this.getInstanceName(),
deployedBlock: this.deployedBlock,
zipDigest: this.zipDigest,
});
}
async saveEvents({ newEvents, lastBlock }: BaseEvents<StakeBurnedEvents> & { newEvents: StakeBurnedEvents[] }) {
await saveDBEvents<StakeBurnedEvents>({
idb: this.idb,
instanceName: this.getInstanceName(),
newEvents,
lastBlock,
});
}
}

View File

@@ -1,2 +1,3 @@
export * from './types';
export * from './base';
export * from './db';

View File

@@ -1,80 +1,140 @@
import { RelayerParams } from '../relayerClient';
export interface BaseEvents<T> {
events: T[];
lastBlock: number | null;
events: T[];
lastBlock: number;
}
export interface CachedEvents<T> extends BaseEvents<T> {
fromCache: boolean;
}
export interface BaseGraphEvents<T> {
events: T[];
lastSyncBlock: number;
events: T[];
lastSyncBlock: number;
}
export interface MinimalEvents {
blockNumber: number;
logIndex: number;
transactionHash: string;
blockNumber: number;
logIndex: number;
transactionHash: string;
}
export type GovernanceEvents = MinimalEvents & {
event: string;
};
export interface GovernanceEvents extends MinimalEvents {
event: string;
}
export type GovernanceProposalCreatedEvents = GovernanceEvents & {
id: number;
proposer: string;
target: string;
startTime: number;
endTime: number;
description: string;
};
export interface GovernanceProposalCreatedEvents extends GovernanceEvents {
id: number;
proposer: string;
target: string;
startTime: number;
endTime: number;
description: string;
}
export type GovernanceVotedEvents = GovernanceEvents & {
proposalId: number;
voter: string;
support: boolean;
votes: string;
from: string;
input: string;
};
export interface GovernanceVotedEvents extends GovernanceEvents {
proposalId: number;
voter: string;
support: boolean;
votes: string;
from: string;
input: string;
}
export type GovernanceDelegatedEvents = GovernanceEvents & {
account: string;
delegateTo: string;
};
export interface GovernanceDelegatedEvents extends GovernanceEvents {
account: string;
delegateTo: string;
}
export type GovernanceUndelegatedEvents = GovernanceEvents & {
account: string;
delegateFrom: string;
};
export interface GovernanceUndelegatedEvents extends GovernanceEvents {
account: string;
delegateFrom: string;
}
export type AllGovernanceEvents =
| GovernanceProposalCreatedEvents
| GovernanceVotedEvents
| GovernanceDelegatedEvents
| GovernanceUndelegatedEvents;
| GovernanceProposalCreatedEvents
| GovernanceVotedEvents
| GovernanceDelegatedEvents
| GovernanceUndelegatedEvents;
export interface RelayerRegistryEvents extends MinimalEvents {
event: string;
}
export interface RelayerRegisteredEvents extends RelayerRegistryEvents, RelayerParams {
ensHash: string;
stakedAmount: string;
}
export interface RelayerUnregisteredEvents extends RelayerRegistryEvents {
relayerAddress: string;
}
export interface WorkerRegisteredEvents extends RelayerRegistryEvents {
relayerAddress: string;
workerAddress: string;
}
export interface WorkerUnregisteredEvents extends RelayerRegistryEvents {
relayerAddress: string;
workerAddress: string;
}
export type AllRelayerRegistryEvents =
| RelayerRegisteredEvents
| RelayerUnregisteredEvents
| WorkerRegisteredEvents
| WorkerUnregisteredEvents;
export interface StakeBurnedEvents extends MinimalEvents {
relayerAddress: string;
amountBurned: string;
instanceAddress: string;
gasFee: string;
relayerFee: string;
timestamp: number;
}
// Deprecated type
export type RegistersEvents = MinimalEvents & RelayerParams;
export type DepositsEvents = MinimalEvents & {
commitment: string;
leafIndex: number;
timestamp: number;
from: string;
};
export interface DepositsEvents extends MinimalEvents {
commitment: string;
leafIndex: number;
timestamp: number;
from: string;
}
export type WithdrawalsEvents = MinimalEvents & {
nullifierHash: string;
to: string;
fee: string;
timestamp: number;
};
export interface WithdrawalsEvents extends MinimalEvents {
nullifierHash: string;
to: string;
fee: string;
timestamp: number;
}
export type EchoEvents = MinimalEvents & {
address: string;
encryptedAccount: string;
};
export interface BaseMultiTornadoEvents {
event: string;
instanceAddress: string;
}
export type EncryptedNotesEvents = MinimalEvents & {
encryptedNote: string;
};
export interface MultiDepositsEvents extends BaseMultiTornadoEvents, DepositsEvents {}
export interface MultiWithdrawalsEvents extends BaseMultiTornadoEvents, WithdrawalsEvents {
relayerAddress: string;
}
export interface EchoEvents extends MinimalEvents {
address: string;
encryptedAccount: string;
}
export interface EncryptedNotesEvents extends MinimalEvents {
encryptedNote: string;
}
export interface TransferEvents extends MinimalEvents {
from: string;
to: string;
value: bigint;
}

View File

@@ -1,13 +1,13 @@
import { Transaction, parseUnits } from 'ethers';
import type { BigNumberish, TransactionLike } from 'ethers';
import type { BigNumberish, JsonRpcApiProvider, TransactionLike } from 'ethers';
import { OvmGasPriceOracle } from './typechain';
const DUMMY_ADDRESS = '0x1111111111111111111111111111111111111111';
const DUMMY_NONCE = '0x1111111111111111111111111111111111111111111111111111111111111111';
const DUMMY_NONCE = 1024;
const DUMMY_WITHDRAW_DATA =
'0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111';
'0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111';
/**
* Example:
@@ -15,110 +15,145 @@ const DUMMY_WITHDRAW_DATA =
* amountInWei (0.1 ETH) * tokenDecimals (18) * tokenPriceInWei (0.0008) = 125 TOKEN
*/
export function convertETHToTokenAmount(
amountInWei: BigNumberish,
tokenPriceInWei: BigNumberish,
tokenDecimals: number = 18,
amountInWei: BigNumberish,
tokenPriceInWei: BigNumberish,
tokenDecimals: number = 18,
): bigint {
const tokenDecimalsMultiplier = BigInt(10 ** Number(tokenDecimals));
return (BigInt(amountInWei) * tokenDecimalsMultiplier) / BigInt(tokenPriceInWei);
const tokenDecimalsMultiplier = BigInt(10 ** Number(tokenDecimals));
return (BigInt(amountInWei) * tokenDecimalsMultiplier) / BigInt(tokenPriceInWei);
}
export interface RelayerFeeParams {
gasPrice: BigNumberish;
gasLimit?: BigNumberish;
l1Fee?: BigNumberish;
denomination: BigNumberish;
ethRefund: BigNumberish;
tokenPriceInWei: BigNumberish;
tokenDecimals: number;
relayerFeePercent?: number;
isEth?: boolean;
premiumPercent?: number;
gasPrice: BigNumberish;
gasLimit?: BigNumberish;
l1Fee?: BigNumberish;
denomination: BigNumberish;
ethRefund: BigNumberish;
tokenPriceInWei: BigNumberish;
tokenDecimals: number;
relayerFeePercent?: number;
isEth?: boolean;
premiumPercent?: number;
}
export class TornadoFeeOracle {
ovmGasPriceOracle?: OvmGasPriceOracle;
provider: JsonRpcApiProvider;
ovmGasPriceOracle?: OvmGasPriceOracle;
constructor(ovmGasPriceOracle?: OvmGasPriceOracle) {
if (ovmGasPriceOracle) {
this.ovmGasPriceOracle = ovmGasPriceOracle;
}
}
constructor(provider: JsonRpcApiProvider, ovmGasPriceOracle?: OvmGasPriceOracle) {
this.provider = provider;
/**
* Calculate L1 fee for op-stack chains
*
* This is required since relayers would pay the full transaction fees for users
*/
fetchL1OptimismFee(tx?: TransactionLike): Promise<bigint> {
if (!this.ovmGasPriceOracle) {
return new Promise((resolve) => resolve(BigInt(0)));
if (ovmGasPriceOracle) {
this.ovmGasPriceOracle = ovmGasPriceOracle;
}
}
if (!tx) {
// this tx is only used to simulate bytes size of the encoded tx so has nothing to with the accuracy
// inspired by the old style classic-ui calculation
tx = {
type: 0,
gasLimit: 1_000_000,
nonce: Number(DUMMY_NONCE),
data: DUMMY_WITHDRAW_DATA,
gasPrice: parseUnits('1', 'gwei'),
from: DUMMY_ADDRESS,
to: DUMMY_ADDRESS,
};
/**
* Calculates Gas Price
* We apply 50% premium of EIP-1559 network fees instead of 100% from ethers.js
* (This should cover up to 4 full blocks which is equivalent of minute)
* (A single block can bump 12.5% of fees, see the methodology https://hackmd.io/@tvanepps/1559-wallets)
* (Still it is recommended to use 100% premium for sending transactions to prevent stucking it)
*/
async gasPrice(premium?: number) {
const [block, getGasPrice, getPriorityFee] = await Promise.all([
this.provider.getBlock('latest'),
(async () => {
try {
return BigInt(await this.provider.send('eth_gasPrice', []));
} catch {
return parseUnits('1', 'gwei');
}
})(),
(async () => {
try {
return BigInt(await this.provider.send('eth_maxPriorityFeePerGas', []));
} catch {
return BigInt(0);
}
})(),
]);
return block?.baseFeePerGas
? (block.baseFeePerGas * BigInt(10000 * (100 + (premium || 50)))) / BigInt(10000 * 100) + getPriorityFee
: getGasPrice;
}
return this.ovmGasPriceOracle.getL1Fee.staticCall(Transaction.from(tx).unsignedSerialized);
}
/**
* Calculate L1 fee for op-stack chains
*
* This is required since relayers would pay the full transaction fees for users
*/
async fetchL1OptimismFee(tx?: TransactionLike): Promise<bigint> {
if (!this.ovmGasPriceOracle) {
return new Promise((resolve) => resolve(BigInt(0)));
}
/**
* We don't need to distinguish default refunds by tokens since most users interact with other defi protocols after withdrawal
* So we default with 1M gas which is enough for two or three swaps
* Using 30 gwei for default but it is recommended to supply cached gasPrice value from the UI
*/
defaultEthRefund(gasPrice?: BigNumberish, gasLimit?: BigNumberish): bigint {
return (gasPrice ? BigInt(gasPrice) : parseUnits('30', 'gwei')) * BigInt(gasLimit || 1_000_000);
}
if (!tx) {
// this tx is only used to simulate bytes size of the encoded tx so has nothing to with the accuracy
// inspired by the old style classic-ui calculation
tx = {
type: 0,
gasLimit: 1_000_000,
nonce: DUMMY_NONCE,
data: DUMMY_WITHDRAW_DATA,
gasPrice: parseUnits('1', 'gwei'),
to: DUMMY_ADDRESS,
};
}
/**
* Calculates token amount for required ethRefund purchases required to calculate fees
*/
calculateTokenAmount(ethRefund: BigNumberish, tokenPriceInEth: BigNumberish, tokenDecimals?: number): bigint {
return convertETHToTokenAmount(ethRefund, tokenPriceInEth, tokenDecimals);
}
/**
* Warning: For tokens you need to check if the fees are above denomination
* (Usually happens for small denomination pool or if the gas price is high)
*/
calculateRelayerFee({
gasPrice,
gasLimit = 600_000,
l1Fee = 0,
denomination,
ethRefund = BigInt(0),
tokenPriceInWei,
tokenDecimals = 18,
relayerFeePercent = 0.33,
isEth = true,
premiumPercent = 20,
}: RelayerFeeParams): bigint {
const gasCosts = BigInt(gasPrice) * BigInt(gasLimit) + BigInt(l1Fee);
const relayerFee = (BigInt(denomination) * BigInt(Math.floor(10000 * relayerFeePercent))) / BigInt(10000 * 100);
if (isEth) {
// Add 20% premium
return ((gasCosts + relayerFee) * BigInt(premiumPercent ? 100 + premiumPercent : 100)) / BigInt(100);
return (
((await this.ovmGasPriceOracle.getL1Fee.staticCall(Transaction.from(tx).unsignedSerialized)) * 12n) / 10n
);
}
const feeInEth = gasCosts + BigInt(ethRefund);
/**
* We don't need to distinguish default refunds by tokens since most users interact with other defi protocols after withdrawal
* So we default with 1M gas which is enough for two or three swaps
* Using 30 gwei for default but it is recommended to supply cached gasPrice value from the UI
*/
defaultEthRefund(gasPrice?: BigNumberish, gasLimit?: BigNumberish): bigint {
return (gasPrice ? BigInt(gasPrice) : parseUnits('30', 'gwei')) * BigInt(gasLimit || 1_000_000);
}
return (
((convertETHToTokenAmount(feeInEth, tokenPriceInWei, tokenDecimals) + relayerFee) *
BigInt(premiumPercent ? 100 + premiumPercent : 100)) /
BigInt(100)
);
}
/**
* Calculates token amount for required ethRefund purchases required to calculate fees
*/
calculateTokenAmount(ethRefund: BigNumberish, tokenPriceInEth: BigNumberish, tokenDecimals?: number): bigint {
return convertETHToTokenAmount(ethRefund, tokenPriceInEth, tokenDecimals);
}
/**
* Warning: For tokens you need to check if the fees are above denomination
* (Usually happens for small denomination pool or if the gas price is high)
*/
calculateRelayerFee({
gasPrice,
gasLimit = 600_000,
l1Fee = 0,
denomination,
ethRefund = BigInt(0),
tokenPriceInWei,
tokenDecimals = 18,
relayerFeePercent = 0.33,
isEth = true,
premiumPercent = 20,
}: RelayerFeeParams): bigint {
const gasCosts = BigInt(gasPrice) * BigInt(gasLimit) + BigInt(l1Fee);
const relayerFee = (BigInt(denomination) * BigInt(Math.floor(10000 * relayerFeePercent))) / BigInt(10000 * 100);
if (isEth) {
// Add 20% premium
return ((gasCosts + relayerFee) * BigInt(premiumPercent ? 100 + premiumPercent : 100)) / BigInt(100);
}
const feeInEth = gasCosts + BigInt(ethRefund);
return (
((convertETHToTokenAmount(feeInEth, tokenPriceInWei, tokenDecimals) + relayerFee) *
BigInt(premiumPercent ? 100 + premiumPercent : 100)) /
BigInt(100)
);
}
}

58
src/gaszip.ts Normal file
View File

@@ -0,0 +1,58 @@
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.BASE]: '0x391E7C679d29bD940d63be94AD22A25d25b5A604',
[NetId.BLAST]: '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.BASE]: 54,
[NetId.BLAST]: 96,
[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 += Number(shorts[i]).toString(16).padStart(4, '0');
}
return data;
}
export function gasZipMinMax(ethUsd: number) {
return {
min: 1 / ethUsd,
max: 50 / ethUsd,
ethUsd,
};
}

File diff suppressed because it is too large Load Diff

8
src/hasher.ts Normal file

File diff suppressed because one or more lines are too long

472
src/idb.ts Normal file
View File

@@ -0,0 +1,472 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { openDB, deleteDB, OpenDBCallbacks, IDBPDatabase } from 'idb';
import { getConfig, NetIdType } from './networkConfig';
export const INDEX_DB_ERROR = 'A mutation operation was attempted on a database that did not allow mutations.';
export interface IDBIndex {
name: string;
unique?: boolean;
}
export interface IDBStores {
name: string;
keyPath?: string;
indexes?: IDBIndex[];
}
export interface IDBConstructor {
dbName: string;
stores?: IDBStores[];
}
export class IndexedDB {
dbExists: boolean;
isBlocked: boolean;
// todo: TestDBSchema on any
options: OpenDBCallbacks<any>;
dbName: string;
dbVersion: number;
db?: IDBPDatabase<any>;
constructor({ dbName, stores }: IDBConstructor) {
this.dbExists = false;
this.isBlocked = false;
this.options = {
upgrade(db) {
Object.values(db.objectStoreNames).forEach((value) => {
db.deleteObjectStore(value);
});
[{ name: 'keyval' }, ...(stores || [])].forEach(({ name, keyPath, indexes }) => {
const store = db.createObjectStore(name, {
keyPath,
autoIncrement: true,
});
if (Array.isArray(indexes)) {
indexes.forEach(({ name, unique = false }) => {
store.createIndex(name, name, { unique });
});
}
});
},
};
this.dbName = dbName;
this.dbVersion = 36;
}
async initDB() {
try {
if (this.dbExists || this.isBlocked) {
return;
}
this.db = await openDB(this.dbName, this.dbVersion, this.options);
this.db.addEventListener('onupgradeneeded', async () => {
await this._removeExist();
});
this.dbExists = true;
} catch (err: any) {
// needed for private mode firefox browser
if (err.message.includes(INDEX_DB_ERROR)) {
console.log('This browser does not support IndexedDB!');
this.isBlocked = true;
return;
}
if (err.message.includes('less than the existing version')) {
console.log(`Upgrading DB ${this.dbName} to ${this.dbVersion}`);
await this._removeExist();
return;
}
console.error(`Method initDB has error: ${err.message}`);
}
}
async _removeExist() {
await deleteDB(this.dbName);
this.dbExists = false;
await this.initDB();
}
async getFromIndex<T>({
storeName,
indexName,
key,
}: {
storeName: string;
indexName: string;
key?: string;
}): Promise<T | undefined> {
await this.initDB();
if (!this.db) {
return;
}
try {
return (await this.db.getFromIndex(storeName, indexName, key)) as T;
} catch (err: any) {
throw new Error(`Method getFromIndex has error: ${err.message}`);
}
}
async getAllFromIndex<T>({
storeName,
indexName,
key,
count,
}: {
storeName: string;
indexName: string;
key?: string;
count?: number;
}): Promise<T> {
await this.initDB();
if (!this.db) {
return [] as T;
}
try {
return (await this.db.getAllFromIndex(storeName, indexName, key, count)) as T;
} catch (err: any) {
throw new Error(`Method getAllFromIndex has error: ${err.message}`);
}
}
async getItem<T>({ storeName, key }: { storeName: string; key: string }): Promise<T | undefined> {
await this.initDB();
if (!this.db) {
return;
}
try {
const store = this.db.transaction(storeName).objectStore(storeName);
return (await store.get(key)) as T;
} catch (err: any) {
throw new Error(`Method getItem has error: ${err.message}`);
}
}
async addItem({ storeName, data, key = '' }: { storeName: string; data: any; key: string }) {
await this.initDB();
if (!this.db) {
return;
}
try {
const tx = this.db.transaction(storeName, 'readwrite');
const isExist = await tx.objectStore(storeName).get(key);
if (!isExist) {
await tx.objectStore(storeName).add(data);
}
} catch (err: any) {
throw new Error(`Method addItem has error: ${err.message}`);
}
}
async putItem({ storeName, data, key }: { storeName: string; data: any; key?: string }) {
await this.initDB();
if (!this.db) {
return;
}
try {
const tx = this.db.transaction(storeName, 'readwrite');
await tx.objectStore(storeName).put(data, key);
} catch (err: any) {
throw new Error(`Method putItem has error: ${err.message}`);
}
}
async deleteItem({ storeName, key }: { storeName: string; key: string }) {
await this.initDB();
if (!this.db) {
return;
}
try {
const tx = this.db.transaction(storeName, 'readwrite');
await tx.objectStore(storeName).delete(key);
} catch (err: any) {
throw new Error(`Method deleteItem has error: ${err.message}`);
}
}
async getAll<T>({ storeName }: { storeName: string }): Promise<T> {
await this.initDB();
if (!this.db) {
return [] as T;
}
try {
const tx = this.db.transaction(storeName, 'readonly');
return (await tx.objectStore(storeName).getAll()) as T;
} catch (err: any) {
throw new Error(`Method getAll has error: ${err.message}`);
}
}
/**
* Simple key-value store inspired by idb-keyval package
*/
getValue<T>(key: string) {
return this.getItem<T>({ storeName: 'keyval', key });
}
setValue(key: string, data: any) {
return this.putItem({ storeName: 'keyval', key, data });
}
delValue(key: string) {
return this.deleteItem({ storeName: 'keyval', key });
}
async clearStore({ storeName, mode = 'readwrite' }: { storeName: string; mode: IDBTransactionMode }) {
await this.initDB();
if (!this.db) {
return;
}
try {
const tx = this.db.transaction(storeName, mode);
await (tx.objectStore(storeName).clear as () => Promise<void>)();
} catch (err: any) {
throw new Error(`Method clearStore has error: ${err.message}`);
}
}
async createTransactions({
storeName,
data,
mode = 'readwrite',
}: {
storeName: string;
data: any;
mode: IDBTransactionMode;
}) {
await this.initDB();
if (!this.db) {
return;
}
try {
const tx = this.db.transaction(storeName, mode);
await (tx.objectStore(storeName).add as (value: any, key?: any) => Promise<any>)(data);
await tx.done;
} catch (err: any) {
throw new Error(`Method createTransactions has error: ${err.message}`);
}
}
async createMultipleTransactions({
storeName,
data,
index,
mode = 'readwrite',
}: {
storeName: string;
data: any[];
index?: any;
mode?: IDBTransactionMode;
}) {
await this.initDB();
if (!this.db) {
return;
}
try {
const tx = this.db.transaction(storeName, mode);
for (const item of data) {
if (item) {
await (tx.store.put as (value: any, key?: any) => Promise<any>)({ ...item, ...index });
}
}
} catch (err: any) {
throw new Error(`Method createMultipleTransactions has error: ${err.message}`);
}
}
}
/**
* Should check if DB is initialized well
*/
export async function getIndexedDB(netId?: NetIdType) {
// key-value db for settings
if (!netId) {
const idb = new IndexedDB({ dbName: 'tornado-core' });
await idb.initDB();
return idb;
}
const minimalIndexes = [
{
name: 'eid',
unique: true,
},
];
const defaultState = [
{
name: `tornado_${netId}`,
keyPath: 'eid',
indexes: [...minimalIndexes],
},
{
name: `echo_${netId}`,
keyPath: 'eid',
indexes: [
...minimalIndexes,
{
name: 'address',
unique: false,
},
],
},
{
name: `encrypted_notes_${netId}`,
keyPath: 'eid',
indexes: minimalIndexes,
},
{
name: 'lastEvents',
keyPath: 'name',
indexes: [
{
name: 'name',
unique: false,
},
],
},
];
const { tokens, nativeCurrency, registryContract, governanceContract } = getConfig(netId);
const stores = [...defaultState];
if (registryContract) {
stores.push({
name: `registry_${netId}`,
keyPath: 'ensName',
indexes: [
...minimalIndexes,
{
name: 'event',
unique: false,
},
],
});
stores.push({
name: `relayers_${netId}`,
keyPath: 'timestamp',
indexes: [
{
name: 'timestamp',
unique: true,
},
],
});
stores.push({
name: `revenue_${netId}`,
keyPath: 'timestamp',
indexes: [
{
name: 'timestamp',
unique: true,
},
],
});
}
if (governanceContract) {
stores.push({
name: `governance_${netId}`,
keyPath: 'eid',
indexes: [
...minimalIndexes,
{
name: 'event',
unique: false,
},
],
});
}
Object.entries(tokens).forEach(([token, { instanceAddress }]) => {
Object.keys(instanceAddress).forEach((amount) => {
if (nativeCurrency === token) {
stores.push(
{
name: `stringify_bloom_${netId}_${token}_${amount}`,
keyPath: 'hashBloom',
indexes: [],
},
{
name: `stringify_tree_${netId}_${token}_${amount}`,
keyPath: 'hashTree',
indexes: [],
},
);
}
stores.push(
{
name: `deposits_${netId}_${token}_${amount}`,
keyPath: 'leafIndex', // the key by which it refers to the object must be in all instances of the storage
indexes: [
...minimalIndexes,
{
name: 'commitment',
unique: true,
},
],
},
{
name: `withdrawals_${netId}_${token}_${amount}`,
keyPath: 'eid',
indexes: [
...minimalIndexes,
{
name: 'nullifierHash',
unique: true,
}, // keys on which the index is created
],
},
);
});
});
const idb = new IndexedDB({
dbName: `tornado_core_${netId}`,
stores,
});
await idb.initDB();
return idb;
}

View File

@@ -1,19 +1,27 @@
export * from './events';
export * from './graphql';
//export * from './graphql';
export * from './schemas';
export * from './typechain';
export * from './batch';
export * from './deposits';
export * from './encryptedNotes';
export * from './ens';
export * from './fees';
export * from './gaszip';
export * from './hasher';
export * from './idb';
export * from './ip';
export * from './merkleTree';
export * from './mimc';
export * from './multicall';
export * from './networkConfig';
export * from './pedersen';
export * from './permit';
export * from './prices';
export * from './providers';
export * from './relayerClient';
export * from './tokens';
export * from './tovarishClient';
export * from './utils';
export * from './websnark';
export * from './zip';

14
src/ip.ts Normal file
View File

@@ -0,0 +1,14 @@
import { fetchData } from './providers';
export interface IPResult {
ip: string;
iso?: string;
tor?: boolean;
}
export async function fetchIp(ipEcho: string) {
return (await fetchData(ipEcho, {
method: 'GET',
timeout: 30000,
})) as IPResult;
}

View File

@@ -1,5 +1,5 @@
import { Worker as NodeWorker } from 'worker_threads';
import { MerkleTree, PartialMerkleTree, Element, TreeEdge } from '@tornado/fixed-merkle-tree';
import { MerkleTree, PartialMerkleTree, Element, TreeEdge } from 'fixed-merkle-tree';
import type { Tornado } from '@tornado/contracts';
import { isNode, toFixedHex } from './utils';
import { mimc } from './mimc';
@@ -7,193 +7,196 @@ import type { DepositType } from './deposits';
import type { DepositsEvents } from './events';
import type { NetIdType } from './networkConfig';
export type MerkleTreeConstructor = DepositType & {
Tornado: Tornado;
commitmentHex?: string;
merkleTreeHeight?: number;
emptyElement?: string;
merkleWorkerPath?: string;
};
export interface MerkleTreeConstructor extends DepositType {
Tornado: Tornado;
commitmentHex?: string;
merkleTreeHeight?: number;
emptyElement?: string;
merkleWorkerPath?: string;
}
export class MerkleTreeService {
currency: string;
amount: string;
netId: NetIdType;
Tornado: Tornado;
commitmentHex?: string;
instanceName: string;
currency: string;
amount: string;
netId: NetIdType;
Tornado: Tornado;
commitmentHex?: string;
instanceName: string;
merkleTreeHeight: number;
emptyElement: string;
merkleTreeHeight: number;
emptyElement: string;
merkleWorkerPath?: string;
merkleWorkerPath?: string;
constructor({
netId,
amount,
currency,
Tornado,
commitmentHex,
merkleTreeHeight = 20,
emptyElement = '21663839004416932945382355908790599225266501822907911457504978515578255421292',
merkleWorkerPath,
}: MerkleTreeConstructor) {
const instanceName = `${netId}_${currency}_${amount}`;
constructor({
netId,
amount,
currency,
Tornado,
commitmentHex,
merkleTreeHeight = 20,
emptyElement = '21663839004416932945382355908790599225266501822907911457504978515578255421292',
merkleWorkerPath,
}: MerkleTreeConstructor) {
const instanceName = `${netId}_${currency}_${amount}`;
this.currency = currency;
this.amount = amount;
this.netId = Number(netId);
this.currency = currency;
this.amount = amount;
this.netId = Number(netId);
this.Tornado = Tornado;
this.instanceName = instanceName;
this.commitmentHex = commitmentHex;
this.Tornado = Tornado;
this.instanceName = instanceName;
this.commitmentHex = commitmentHex;
this.merkleTreeHeight = merkleTreeHeight;
this.emptyElement = emptyElement;
this.merkleWorkerPath = merkleWorkerPath;
}
this.merkleTreeHeight = merkleTreeHeight;
this.emptyElement = emptyElement;
this.merkleWorkerPath = merkleWorkerPath;
}
async createTree(events: Element[]) {
const { hash: hashFunction } = await mimc.getHash();
async createTree(events: Element[]) {
const { hash: hashFunction } = await mimc.getHash();
if (this.merkleWorkerPath) {
console.log('Using merkleWorker\n');
if (this.merkleWorkerPath) {
console.log('Using merkleWorker\n');
try {
if (isNode) {
const merkleWorkerPromise = new Promise((resolve, reject) => {
const worker = new NodeWorker(this.merkleWorkerPath as string, {
workerData: {
merkleTreeHeight: this.merkleTreeHeight,
elements: events,
zeroElement: this.emptyElement,
},
});
worker.on('message', resolve);
worker.on('error', reject);
worker.on('exit', (code) => {
if (code !== 0) {
reject(new Error(`Worker stopped with exit code ${code}`));
}
});
}) as Promise<string>;
try {
if (isNode) {
const merkleWorkerPromise = new Promise((resolve, reject) => {
const worker = new NodeWorker(this.merkleWorkerPath as string, {
workerData: {
merkleTreeHeight: this.merkleTreeHeight,
elements: events,
zeroElement: this.emptyElement,
},
});
worker.on('message', resolve);
worker.on('error', reject);
worker.on('exit', (code) => {
if (code !== 0) {
reject(new Error(`Worker stopped with exit code ${code}`));
}
});
}) as Promise<string>;
return MerkleTree.deserialize(JSON.parse(await merkleWorkerPromise), hashFunction);
} else {
const merkleWorkerPromise = new Promise((resolve, reject) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const worker = new (Worker as any)(this.merkleWorkerPath);
return MerkleTree.deserialize(JSON.parse(await merkleWorkerPromise), hashFunction);
} else {
const merkleWorkerPromise = new Promise((resolve, reject) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const worker = new (Worker as any)(this.merkleWorkerPath);
worker.onmessage = (e: { data: string }) => {
resolve(e.data);
};
worker.onmessage = (e: { data: string }) => {
resolve(e.data);
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
worker.onerror = (e: any) => {
reject(e);
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
worker.onerror = (e: any) => {
reject(e);
};
worker.postMessage({
merkleTreeHeight: this.merkleTreeHeight,
elements: events,
zeroElement: this.emptyElement,
});
}) as Promise<string>;
worker.postMessage({
merkleTreeHeight: this.merkleTreeHeight,
elements: events,
zeroElement: this.emptyElement,
});
}) as Promise<string>;
return MerkleTree.deserialize(JSON.parse(await merkleWorkerPromise), hashFunction);
return MerkleTree.deserialize(JSON.parse(await merkleWorkerPromise), hashFunction);
}
} catch (err) {
console.log('merkleWorker failed, falling back to synchronous merkle tree');
console.log(err);
}
}
} catch (err) {
console.log('merkleWorker failed, falling back to synchronous merkle tree');
console.log(err);
}
return new MerkleTree(this.merkleTreeHeight, events, {
zeroElement: this.emptyElement,
hashFunction,
});
}
return new MerkleTree(this.merkleTreeHeight, events, {
zeroElement: this.emptyElement,
hashFunction,
});
}
async createPartialTree({ edge, elements }: { edge: TreeEdge; elements: Element[] }) {
const { hash: hashFunction } = await mimc.getHash();
async createPartialTree({ edge, elements }: { edge: TreeEdge; elements: Element[] }) {
const { hash: hashFunction } = await mimc.getHash();
if (this.merkleWorkerPath) {
console.log('Using merkleWorker\n');
if (this.merkleWorkerPath) {
console.log('Using merkleWorker\n');
try {
if (isNode) {
const merkleWorkerPromise = new Promise((resolve, reject) => {
const worker = new NodeWorker(this.merkleWorkerPath as string, {
workerData: {
merkleTreeHeight: this.merkleTreeHeight,
edge,
elements,
zeroElement: this.emptyElement,
},
});
worker.on('message', resolve);
worker.on('error', reject);
worker.on('exit', (code) => {
if (code !== 0) {
reject(new Error(`Worker stopped with exit code ${code}`));
}
});
}) as Promise<string>;
try {
if (isNode) {
const merkleWorkerPromise = new Promise((resolve, reject) => {
const worker = new NodeWorker(this.merkleWorkerPath as string, {
workerData: {
merkleTreeHeight: this.merkleTreeHeight,
edge,
elements,
zeroElement: this.emptyElement,
},
});
worker.on('message', resolve);
worker.on('error', reject);
worker.on('exit', (code) => {
if (code !== 0) {
reject(new Error(`Worker stopped with exit code ${code}`));
}
});
}) as Promise<string>;
return PartialMerkleTree.deserialize(JSON.parse(await merkleWorkerPromise), hashFunction);
} else {
const merkleWorkerPromise = new Promise((resolve, reject) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const worker = new (Worker as any)(this.merkleWorkerPath);
return PartialMerkleTree.deserialize(JSON.parse(await merkleWorkerPromise), hashFunction);
} else {
const merkleWorkerPromise = new Promise((resolve, reject) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const worker = new (Worker as any)(this.merkleWorkerPath);
worker.onmessage = (e: { data: string }) => {
resolve(e.data);
};
worker.onmessage = (e: { data: string }) => {
resolve(e.data);
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
worker.onerror = (e: any) => {
reject(e);
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
worker.onerror = (e: any) => {
reject(e);
};
worker.postMessage({
merkleTreeHeight: this.merkleTreeHeight,
edge,
elements,
zeroElement: this.emptyElement,
});
}) as Promise<string>;
worker.postMessage({
merkleTreeHeight: this.merkleTreeHeight,
edge,
elements,
zeroElement: this.emptyElement,
});
}) as Promise<string>;
return PartialMerkleTree.deserialize(JSON.parse(await merkleWorkerPromise), hashFunction);
return PartialMerkleTree.deserialize(JSON.parse(await merkleWorkerPromise), hashFunction);
}
} catch (err) {
console.log('merkleWorker failed, falling back to synchronous merkle tree');
console.log(err);
}
}
} catch (err) {
console.log('merkleWorker failed, falling back to synchronous merkle tree');
console.log(err);
}
return new PartialMerkleTree(this.merkleTreeHeight, edge, elements, {
zeroElement: this.emptyElement,
hashFunction,
});
}
return new PartialMerkleTree(this.merkleTreeHeight, edge, elements, {
zeroElement: this.emptyElement,
hashFunction,
});
}
async verifyTree(events: DepositsEvents[]) {
console.log(
`\nCreating deposit tree for ${this.netId} ${this.amount} ${this.currency.toUpperCase()} would take a while\n`,
);
async verifyTree(events: DepositsEvents[]) {
console.log(
`\nCreating deposit tree for ${this.netId} ${this.amount} ${this.currency.toUpperCase()} would take a while\n`,
);
const timeStart = Date.now();
console.time('Created tree in');
const tree = await this.createTree(events.map(({ commitment }) => commitment));
console.timeEnd('Created tree in');
console.log('');
const tree = await this.createTree(events.map(({ commitment }) => commitment));
const isKnownRoot = await this.Tornado.isKnownRoot(toFixedHex(BigInt(tree.root)));
const isKnownRoot = await this.Tornado.isKnownRoot(toFixedHex(BigInt(tree.root)));
if (!isKnownRoot) {
const errMsg = `Deposit Event ${this.netId} ${this.amount} ${this.currency} is invalid`;
throw new Error(errMsg);
if (!isKnownRoot) {
const errMsg = `Deposit Event ${this.netId} ${this.amount} ${this.currency} is invalid`;
throw new Error(errMsg);
}
console.log(
`\nCreated ${this.netId} ${this.amount} ${this.currency.toUpperCase()} tree in ${Date.now() - timeStart}ms\n`,
);
return tree;
}
return tree;
}
}

View File

@@ -1,70 +1,70 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import workerThreads from 'worker_threads';
import { MerkleTree, Element, TreeEdge, PartialMerkleTree } from '@tornado/fixed-merkle-tree';
import { MerkleTree, Element, TreeEdge, PartialMerkleTree } from 'fixed-merkle-tree';
import { mimc } from './mimc';
import { isNode } from './utils';
interface WorkData {
merkleTreeHeight: number;
edge?: TreeEdge;
elements: Element[];
zeroElement: string;
merkleTreeHeight: number;
edge?: TreeEdge;
elements: Element[];
zeroElement: string;
}
async function nodePostWork() {
const { hash: hashFunction } = await mimc.getHash();
const { merkleTreeHeight, edge, elements, zeroElement } = workerThreads.workerData as WorkData;
if (edge) {
const merkleTree = new PartialMerkleTree(merkleTreeHeight, edge, elements, {
zeroElement,
hashFunction,
});
(workerThreads.parentPort as workerThreads.MessagePort).postMessage(merkleTree.toString());
return;
}
const merkleTree = new MerkleTree(merkleTreeHeight, elements, {
zeroElement,
hashFunction,
});
(workerThreads.parentPort as workerThreads.MessagePort).postMessage(merkleTree.toString());
}
if (isNode && workerThreads) {
nodePostWork();
} else if (!isNode && typeof addEventListener === 'function' && typeof postMessage === 'function') {
addEventListener('message', async (e: any) => {
let data;
if (e.data) {
data = e.data;
} else {
data = e;
}
const { hash: hashFunction } = await mimc.getHash();
const { merkleTreeHeight, edge, elements, zeroElement } = data as WorkData;
const { merkleTreeHeight, edge, elements, zeroElement } = workerThreads.workerData as WorkData;
if (edge) {
const merkleTree = new PartialMerkleTree(merkleTreeHeight, edge, elements, {
zeroElement,
hashFunction,
});
const merkleTree = new PartialMerkleTree(merkleTreeHeight, edge, elements, {
zeroElement,
hashFunction,
});
postMessage(merkleTree.toString());
return;
(workerThreads.parentPort as workerThreads.MessagePort).postMessage(merkleTree.toString());
return;
}
const merkleTree = new MerkleTree(merkleTreeHeight, elements, {
zeroElement,
hashFunction,
zeroElement,
hashFunction,
});
postMessage(merkleTree.toString());
});
} else {
throw new Error('This browser / environment does not support workers!');
(workerThreads.parentPort as workerThreads.MessagePort).postMessage(merkleTree.toString());
}
if (isNode && workerThreads) {
nodePostWork();
} else if (!isNode && typeof addEventListener === 'function' && typeof postMessage === 'function') {
addEventListener('message', async (e: any) => {
let data;
if (e.data) {
data = e.data;
} else {
data = e;
}
const { hash: hashFunction } = await mimc.getHash();
const { merkleTreeHeight, edge, elements, zeroElement } = data as WorkData;
if (edge) {
const merkleTree = new PartialMerkleTree(merkleTreeHeight, edge, elements, {
zeroElement,
hashFunction,
});
postMessage(merkleTree.toString());
return;
}
const merkleTree = new MerkleTree(merkleTreeHeight, elements, {
zeroElement,
hashFunction,
});
postMessage(merkleTree.toString());
});
} else {
throw new Error('This browser / environment does not support workers!');
}

View File

@@ -1,28 +1,28 @@
import { MimcSponge, buildMimcSponge } from 'circomlibjs';
import type { Element, HashFunction } from '@tornado/fixed-merkle-tree';
import type { Element, HashFunction } from 'fixed-merkle-tree';
export class Mimc {
sponge?: MimcSponge;
hash?: HashFunction<Element>;
mimcPromise: Promise<void>;
sponge?: MimcSponge;
hash?: HashFunction<Element>;
mimcPromise: Promise<void>;
constructor() {
this.mimcPromise = this.initMimc();
}
constructor() {
this.mimcPromise = this.initMimc();
}
async initMimc() {
this.sponge = await buildMimcSponge();
this.hash = (left, right) => this.sponge?.F.toString(this.sponge?.multiHash([BigInt(left), BigInt(right)]));
}
async initMimc() {
this.sponge = await buildMimcSponge();
this.hash = (left, right) => this.sponge?.F.toString(this.sponge?.multiHash([BigInt(left), BigInt(right)]));
}
async getHash() {
await this.mimcPromise;
async getHash() {
await this.mimcPromise;
return {
sponge: this.sponge,
hash: this.hash,
};
}
return {
sponge: this.sponge,
hash: this.hash,
};
}
}
export const mimc = new Mimc();

View File

@@ -2,36 +2,36 @@ import { BaseContract, Interface } from 'ethers';
import { Multicall } from './typechain';
export interface Call3 {
contract?: BaseContract;
address?: string;
interface?: Interface;
name: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
params?: any[];
allowFailure?: boolean;
contract?: BaseContract;
address?: string;
interface?: Interface;
name: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
params?: any[];
allowFailure?: boolean;
}
export async function multicall(Multicall: Multicall, calls: Call3[]) {
const calldata = calls.map((call) => {
const target = (call.contract?.target || call.address) as string;
const callInterface = (call.contract?.interface || call.interface) as Interface;
const calldata = calls.map((call) => {
const target = (call.contract?.target || call.address) as string;
const callInterface = (call.contract?.interface || call.interface) as Interface;
return {
target,
callData: callInterface.encodeFunctionData(call.name, call.params),
allowFailure: call.allowFailure ?? false,
};
});
return {
target,
callData: callInterface.encodeFunctionData(call.name, call.params),
allowFailure: call.allowFailure ?? false,
};
});
const returnData = await Multicall.aggregate3.staticCall(calldata);
const returnData = await Multicall.aggregate3.staticCall(calldata);
const res = returnData.map((call, i) => {
const callInterface = (calls[i].contract?.interface || calls[i].interface) as Interface;
const [result, data] = call;
const decodeResult =
result && data && data !== '0x' ? callInterface.decodeFunctionResult(calls[i].name, data) : null;
return !decodeResult ? null : decodeResult.length === 1 ? decodeResult[0] : decodeResult;
});
const res = returnData.map((call, i) => {
const callInterface = (calls[i].contract?.interface || calls[i].interface) as Interface;
const [result, data] = call;
const decodeResult =
result && data && data !== '0x' ? callInterface.decodeFunctionResult(calls[i].name, data) : null;
return !decodeResult ? null : decodeResult.length === 1 ? decodeResult[0] : decodeResult;
});
return res;
return res;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,32 +1,32 @@
import { BabyJub, PedersenHash, Point, buildPedersenHash } from 'circomlibjs';
export class Pedersen {
pedersenHash?: PedersenHash;
babyJub?: BabyJub;
pedersenPromise: Promise<void>;
pedersenHash?: PedersenHash;
babyJub?: BabyJub;
pedersenPromise: Promise<void>;
constructor() {
this.pedersenPromise = this.initPedersen();
}
constructor() {
this.pedersenPromise = this.initPedersen();
}
async initPedersen() {
this.pedersenHash = await buildPedersenHash();
this.babyJub = this.pedersenHash.babyJub;
}
async initPedersen() {
this.pedersenHash = await buildPedersenHash();
this.babyJub = this.pedersenHash.babyJub;
}
async unpackPoint(buffer: Uint8Array) {
await this.pedersenPromise;
return this.babyJub?.unpackPoint(this.pedersenHash?.hash(buffer) as Uint8Array);
}
async unpackPoint(buffer: Uint8Array) {
await this.pedersenPromise;
return this.babyJub?.unpackPoint(this.pedersenHash?.hash(buffer) as Uint8Array);
}
toStringBuffer(buffer: Uint8Array): string {
return this.babyJub?.F.toString(buffer);
}
toStringBuffer(buffer: Uint8Array): string {
return this.babyJub?.F.toString(buffer);
}
}
export const pedersen = new Pedersen();
export async function buffPedersenHash(buffer: Uint8Array): Promise<string> {
const [hash] = (await pedersen.unpackPoint(buffer)) as Point;
return pedersen.toStringBuffer(hash);
const [hash] = (await pedersen.unpackPoint(buffer)) as Point;
return pedersen.toStringBuffer(hash);
}

234
src/permit.ts Normal file
View File

@@ -0,0 +1,234 @@
import { ERC20Permit, ERC20Mock, TORN } from '@tornado/contracts';
import { MaxUint256, Provider, Signature, Signer, TypedDataField } from 'ethers';
export interface PermitValue {
spender: string;
value: bigint;
nonce?: bigint;
deadline?: bigint;
}
export interface PermitCommitments {
denomination: bigint;
commitments: string[];
nonce?: bigint;
deadline?: bigint;
}
export const permit2Address = '0x000000000022D473030F116dDEE9F6B43aC78BA3';
/**
* From @uniswap/permit2-sdk ported for ethers.js v6
*/
export interface Witness {
witnessTypeName: string;
witnessType: {
[key: string]: TypedDataField[];
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
witness: any;
}
export async function getPermitSignature({
Token,
signer,
spender,
value,
nonce,
deadline,
}: PermitValue & {
Token: ERC20Permit | ERC20Mock | TORN;
signer?: Signer;
}) {
const sigSigner = (signer || Token.runner) as Signer & { address: string };
const provider = sigSigner.provider as Provider;
const [name, lastNonce, { chainId }] = await Promise.all([
Token.name(),
Token.nonces(sigSigner.address),
provider.getNetwork(),
]);
const DOMAIN_SEPARATOR = {
name,
version: '1',
chainId,
verifyingContract: Token.target as string,
};
const PERMIT_TYPE = {
Permit: [
{ name: 'owner', type: 'address' },
{ name: 'spender', type: 'address' },
{ name: 'value', type: 'uint256' },
{ name: 'nonce', type: 'uint256' },
{ name: 'deadline', type: 'uint256' },
],
};
return Signature.from(
await sigSigner.signTypedData(DOMAIN_SEPARATOR, PERMIT_TYPE, {
owner: sigSigner.address,
spender,
value,
nonce: nonce || lastNonce,
deadline: deadline || MaxUint256,
}),
);
}
/**
export async function getPermitCommitmentsSignature({
PermitTornado,
Token,
signer,
denomination,
commitments,
nonce,
}: PermitCommitments & {
PermitTornado: PermitTornado;
Token: ERC20Permit | ERC20Mock | TORN;
signer?: Signer;
}) {
const value = BigInt(commitments.length) * denomination;
const commitmentsHash = solidityPackedKeccak256(['bytes32[]'], [commitments]);
return await getPermitSignature({
Token,
signer,
spender: PermitTornado.target as string,
value,
nonce,
deadline: BigInt(commitmentsHash),
});
}
export async function getPermit2Signature({
Token,
signer,
spender,
value: amount,
nonce,
deadline,
witness,
}: PermitValue & {
Token: BaseContract;
signer?: Signer;
witness?: Witness;
}) {
const sigSigner = (signer || Token.runner) as Signer & { address: string };
const provider = sigSigner.provider as Provider;
const domain = {
name: 'Permit2',
chainId: (await provider.getNetwork()).chainId,
verifyingContract: permit2Address,
};
const types: {
[key: string]: TypedDataField[];
} = !witness
? {
PermitTransferFrom: [
{ name: 'permitted', type: 'TokenPermissions' },
{ name: 'spender', type: 'address' },
{ name: 'nonce', type: 'uint256' },
{ name: 'deadline', type: 'uint256' },
],
TokenPermissions: [
{ name: 'token', type: 'address' },
{ name: 'amount', type: 'uint256' },
],
}
: {
PermitWitnessTransferFrom: [
{ name: 'permitted', type: 'TokenPermissions' },
{ name: 'spender', type: 'address' },
{ name: 'nonce', type: 'uint256' },
{ name: 'deadline', type: 'uint256' },
{ name: 'witness', type: witness.witnessTypeName },
],
TokenPermissions: [
{ name: 'token', type: 'address' },
{ name: 'amount', type: 'uint256' },
],
...witness.witnessType,
};
const values: {
permitted: {
token: string;
amount: bigint;
};
spender: string;
nonce: bigint;
deadline: bigint;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
witness?: any;
} = {
permitted: {
token: Token.target as string,
amount,
},
spender,
// Sorted nonce are not required for Permit2
nonce: nonce || rBigInt(16),
deadline: deadline || MaxUint256,
};
if (witness) {
values.witness = witness.witness;
}
const hash = new TypedDataEncoder(types).hash(values);
const signature = Signature.from(await sigSigner.signTypedData(domain, types, values));
return {
domain,
types,
values,
hash,
signature,
};
}
export async function getPermit2CommitmentsSignature({
PermitTornado,
Token,
signer,
denomination,
commitments,
nonce,
deadline,
}: PermitCommitments & {
PermitTornado: PermitTornado;
Token: BaseContract;
signer?: Signer;
}) {
const value = BigInt(commitments.length) * denomination;
const commitmentsHash = solidityPackedKeccak256(['bytes32[]'], [commitments]);
return await getPermit2Signature({
Token,
signer,
spender: PermitTornado.target as string,
value,
nonce,
deadline,
witness: {
witnessTypeName: 'PermitCommitments',
witnessType: {
PermitCommitments: [
{ name: 'instance', type: 'address' },
{ name: 'commitmentsHash', type: 'bytes32' },
],
},
witness: {
instance: PermitTornado.target,
commitmentsHash,
},
},
});
}
**/

View File

@@ -1,40 +1,103 @@
import { parseEther, type Provider } from 'ethers';
import type { OffchainOracle, Multicall } from './typechain';
import { multicall } from './multicall';
import { formatEther, parseEther, type Provider } from 'ethers';
import { ERC20__factory, OffchainOracle, Multicall } from './typechain';
import { multicall, Call3 } from './multicall';
export class TokenPriceOracle {
oracle?: OffchainOracle;
multicall: Multicall;
provider: Provider;
oracle?: OffchainOracle;
multicall: Multicall;
provider: Provider;
constructor(provider: Provider, multicall: Multicall, oracle?: OffchainOracle) {
this.provider = provider;
this.multicall = multicall;
this.oracle = oracle;
}
fallbackPrice: bigint;
async fetchPrices(
tokens: {
tokenAddress: string;
decimals: number;
}[],
): Promise<bigint[]> {
// setup mock price for testnets
if (!this.oracle) {
return new Promise((resolve) => resolve(tokens.map(() => parseEther('0.0001'))));
constructor(provider: Provider, multicall: Multicall, oracle?: OffchainOracle) {
this.provider = provider;
this.multicall = multicall;
this.oracle = oracle;
this.fallbackPrice = parseEther('0.0001');
}
const prices = (await multicall(
this.multicall,
tokens.map(({ tokenAddress }) => ({
contract: this.oracle,
name: 'getRateToEth',
params: [tokenAddress, true],
})),
)) as bigint[];
buildCalls(
tokens: {
tokenAddress: string;
decimals: number;
}[],
): Call3[] {
return tokens.map(({ tokenAddress }) => ({
contract: this.oracle,
name: 'getRateToEth',
params: [tokenAddress, true],
allowFailure: true,
}));
}
return prices.map((price, index) => {
return (price * BigInt(10 ** tokens[index].decimals)) / BigInt(10 ** 18);
});
}
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],
allowFailure: true,
},
];
}
async fetchPrice(tokenAddress: string, decimals: number): Promise<bigint> {
// setup mock price for testnets
if (!this.oracle) {
return new Promise((resolve) => resolve(this.fallbackPrice));
}
try {
const price = await this.oracle.getRateToEth(tokenAddress, true);
return (price * BigInt(10 ** decimals)) / BigInt(10 ** 18);
} catch (err) {
console.log(
`Failed to fetch oracle price for ${tokenAddress}, will use fallback price ${this.fallbackPrice}`,
);
console.log(err);
return this.fallbackPrice;
}
}
async fetchPrices(
tokens: {
tokenAddress: string;
decimals: number;
}[],
): Promise<bigint[]> {
// setup mock price for testnets
if (!this.oracle) {
return new Promise((resolve) => resolve(tokens.map(() => this.fallbackPrice)));
}
const prices = (await multicall(this.multicall, this.buildCalls(tokens))) as (bigint | null)[];
return prices.map((price, index) => {
if (!price) {
price = this.fallbackPrice;
}
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(10 ** 18 / Number(this.fallbackPrice)));
}
const [decimals, price] = await multicall(this.multicall, this.buildStable(stablecoinAddress));
// eth wei price of usdc token
const ethPrice = ((price || this.fallbackPrice) * BigInt(10n ** decimals)) / BigInt(10 ** 18);
return 1 / Number(formatEther(ethPrice));
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,96 +1,103 @@
import { getAddress, namehash, parseEther } from 'ethers';
import type { Aggregator } from '@tornado/contracts';
import type { RelayerStructOutput } from '@tornado/contracts/dist/contracts/Governance/Aggregator/Aggregator';
import { getAddress, parseEther } from 'ethers';
import { sleep } from './utils';
import { NetId, NetIdType, Config } from './networkConfig';
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 { CachedRelayerInfo } from './events';
export const MIN_FEE = 0.1;
export const MAX_FEE = 0.9;
export const MIN_STAKE_BALANCE = parseEther('500');
export interface RelayerParams {
ensName: string;
relayerAddress?: string;
ensName: string;
relayerAddress: string;
}
export interface Relayer {
netId: NetIdType;
url: string;
hostname: string;
rewardAccount: string;
instances: string[];
gasPrice?: number;
ethPrices?: {
[key in string]: string;
};
currentQueue: number;
tornadoServiceFee: number;
/**
* Info from relayer status
*/
export interface RelayerInfo extends RelayerParams {
netId: NetIdType;
url: string;
hostname: string;
rewardAccount: string;
instances: string[];
stakeBalance?: string;
gasPrice?: number;
ethPrices?: {
[key in string]: string;
};
currentQueue: number;
tornadoServiceFee: number;
}
export type RelayerInfo = Relayer & {
ensName: string;
stakeBalance: bigint;
relayerAddress: string;
};
export type RelayerError = {
hostname: string;
relayerAddress?: string;
errorMessage?: string;
};
export interface RelayerError {
hostname: string;
relayerAddress?: string;
errorMessage?: string;
hasError: boolean;
}
export interface RelayerStatus {
url: string;
rewardAccount: string;
instances: {
[key in string]: {
instanceAddress: {
[key in string]: string;
};
tokenAddress?: string;
symbol: string;
decimals: number;
url: string;
rewardAccount: string;
instances: {
[key in string]: {
instanceAddress: {
[key in string]: string;
};
tokenAddress?: string;
symbol: string;
decimals: number;
};
};
};
gasPrices?: {
fast: number;
additionalProperties?: number;
};
netId: NetIdType;
ethPrices?: {
[key in string]: string;
};
tornadoServiceFee: number;
latestBlock?: number;
version: string;
health: {
status: string;
error: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
errorsLog: any[];
};
currentQueue: number;
gasPrices?: {
fast: number;
additionalProperties?: number;
};
netId: NetIdType;
ethPrices?: {
[key in string]: string;
};
tornadoServiceFee: number;
latestBlock?: number;
version: string;
health: {
status: string;
error: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
errorsLog: any[];
};
currentQueue: number;
}
export interface TornadoWithdrawParams extends snarkProofs {
contract: string;
}
export interface RelayerTornadoWithdraw {
id?: string;
error?: string;
id?: string;
error?: string;
}
export interface RelayerTornadoJobs {
error?: string;
id: string;
type?: string;
status: string;
contract?: string;
proof?: string;
args?: string[];
txHash?: string;
confirmations?: number;
failedReason?: string;
error?: string;
id: string;
type?: string;
status: string;
contract?: string;
proof?: string;
args?: string[];
txHash?: string;
confirmations?: number;
failedReason?: string;
}
/**
const semVerRegex =
/^(?<major>0|[1-9]\d*)\.(?<minor>0|[1-9]\d*)\.(?<patch>0|[1-9]\d*)(?:-(?<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
@@ -116,319 +123,298 @@ export function isRelayerUpdated(relayerVersion: string, netId: NetIdType) {
if (prerelease) return false;
return isUpdatedMajor && (Number(patch) >= 5 || netId !== NetId.MAINNET); // Patch checking - also backwards compatibility for Mainnet
}
**/
export function calculateScore({ stakeBalance, tornadoServiceFee }: RelayerInfo, minFee = 0.33, maxFee = 0.53) {
if (tornadoServiceFee < minFee) {
tornadoServiceFee = minFee;
} else if (tornadoServiceFee >= maxFee) {
return BigInt(0);
}
export function calculateScore({ stakeBalance, tornadoServiceFee }: RelayerInfo) {
if (tornadoServiceFee < MIN_FEE) {
tornadoServiceFee = MIN_FEE;
} else if (tornadoServiceFee >= MAX_FEE) {
return BigInt(0);
}
const serviceFeeCoefficient = (tornadoServiceFee - minFee) ** 2;
const feeDiffCoefficient = 1 / (maxFee - minFee) ** 2;
const coefficientsMultiplier = 1 - feeDiffCoefficient * serviceFeeCoefficient;
const serviceFeeCoefficient = (tornadoServiceFee - MIN_FEE) ** 2;
const feeDiffCoefficient = 1 / (MAX_FEE - MIN_FEE) ** 2;
const coefficientsMultiplier = 1 - feeDiffCoefficient * serviceFeeCoefficient;
return BigInt(Math.floor(Number(stakeBalance) * coefficientsMultiplier));
return BigInt(Math.floor(Number(stakeBalance || '0') * coefficientsMultiplier));
}
export function getWeightRandom(weightsScores: bigint[], random: bigint) {
for (let i = 0; i < weightsScores.length; i++) {
if (random < weightsScores[i]) {
return i;
for (let i = 0; i < weightsScores.length; i++) {
if (random < weightsScores[i]) {
return i;
}
random = random - weightsScores[i];
}
random = random - weightsScores[i];
}
return Math.floor(Math.random() * weightsScores.length);
return Math.floor(Math.random() * weightsScores.length);
}
export type RelayerInstanceList = {
[key in string]: {
instanceAddress: {
[key in string]: string;
export interface RelayerInstanceList {
[key: string]: {
instanceAddress: {
[key: string]: string;
};
};
};
};
}
export function getSupportedInstances(instanceList: RelayerInstanceList) {
const rawList = Object.values(instanceList)
.map(({ instanceAddress }) => {
return Object.values(instanceAddress);
})
.flat();
const rawList = Object.values(instanceList)
.map(({ instanceAddress }) => {
return Object.values(instanceAddress);
})
.flat();
return rawList.map((l) => getAddress(l));
return rawList.map((l) => getAddress(l));
}
export function pickWeightedRandomRelayer(relayers: RelayerInfo[], netId: NetIdType) {
let minFee: number, maxFee: number;
export function pickWeightedRandomRelayer(relayers: RelayerInfo[]) {
const weightsScores = relayers.map((el) => calculateScore(el));
const totalWeight = weightsScores.reduce((acc, curr) => {
return (acc = acc + curr);
}, BigInt('0'));
if (netId !== NetId.MAINNET) {
minFee = 0.01;
maxFee = 0.3;
}
const random = BigInt(Math.floor(Number(totalWeight) * Math.random()));
const weightRandomIndex = getWeightRandom(weightsScores, random);
const weightsScores = relayers.map((el) => calculateScore(el, minFee, maxFee));
const totalWeight = weightsScores.reduce((acc, curr) => {
return (acc = acc + curr);
}, BigInt('0'));
const random = BigInt(Number(totalWeight) * Math.random());
const weightRandomIndex = getWeightRandom(weightsScores, random);
return relayers[weightRandomIndex];
return relayers[weightRandomIndex];
}
export interface RelayerClientConstructor {
netId: NetIdType;
config: Config;
Aggregator: Aggregator;
fetchDataOptions?: fetchDataOptions;
netId: NetIdType;
config: Config;
fetchDataOptions?: fetchDataOptions;
}
export type RelayerClientWithdraw = snarkProofs & {
contract: string;
};
export class RelayerClient {
netId: NetIdType;
config: Config;
Aggregator: Aggregator;
selectedRelayer?: Relayer;
fetchDataOptions?: fetchDataOptions;
netId: NetIdType;
config: Config;
selectedRelayer?: RelayerInfo;
fetchDataOptions?: fetchDataOptions;
tovarish: boolean;
constructor({ netId, config, Aggregator, fetchDataOptions }: RelayerClientConstructor) {
this.netId = netId;
this.config = config;
this.Aggregator = Aggregator;
this.fetchDataOptions = fetchDataOptions;
}
async askRelayerStatus({
hostname,
relayerAddress,
}: {
hostname: string;
relayerAddress?: string;
}): Promise<RelayerStatus> {
const url = `https://${!hostname.endsWith('/') ? hostname + '/' : hostname}`;
const rawStatus = (await fetchData(`${url}status`, {
...this.fetchDataOptions,
headers: {
'Content-Type': 'application/json, application/x-www-form-urlencoded',
},
timeout: this.fetchDataOptions?.torPort ? 10000 : 3000,
maxRetry: this.fetchDataOptions?.torPort ? 2 : 0,
})) as object;
const statusValidator = ajv.compile(getStatusSchema(this.netId, this.config));
if (!statusValidator(rawStatus)) {
throw new Error('Invalid status schema');
constructor({ netId, config, fetchDataOptions }: RelayerClientConstructor) {
this.netId = netId;
this.config = config;
this.fetchDataOptions = fetchDataOptions;
this.tovarish = false;
}
const status = {
...rawStatus,
url,
} as RelayerStatus;
if (status.currentQueue > 5) {
throw new Error('Withdrawal queue is overloaded');
}
if (status.netId !== this.netId) {
throw new Error('This relayer serves a different network');
}
if (relayerAddress && this.netId === NetId.MAINNET && status.rewardAccount !== relayerAddress) {
throw new Error('The Relayer reward address must match registered address');
}
if (!isRelayerUpdated(status.version, this.netId)) {
throw new Error('Outdated version.');
}
return status;
}
async filterRelayer(
curr: RelayerStructOutput,
relayer: RelayerParams,
subdomains: string[],
debugRelayer: boolean = false,
): Promise<RelayerInfo | RelayerError> {
const { relayerEnsSubdomain } = this.config;
const subdomainIndex = subdomains.indexOf(relayerEnsSubdomain);
const mainnetSubdomain = curr.records[0];
const hostname = curr.records[subdomainIndex];
const isHostWithProtocol = hostname.includes('http');
const { owner, balance: stakeBalance, isRegistered } = curr;
const { ensName, relayerAddress } = relayer;
const isOwner = !relayerAddress || relayerAddress === owner;
const hasMinBalance = stakeBalance >= MIN_STAKE_BALANCE;
const preCondition =
hostname && isOwner && mainnetSubdomain && isRegistered && hasMinBalance && !isHostWithProtocol;
if (preCondition || debugRelayer) {
try {
const status = await this.askRelayerStatus({ hostname, relayerAddress });
return {
netId: status.netId,
url: status.url,
hostname,
ensName,
stakeBalance,
relayerAddress,
rewardAccount: getAddress(status.rewardAccount),
instances: getSupportedInstances(status.instances),
gasPrice: status.gasPrices?.fast,
ethPrices: status.ethPrices,
currentQueue: status.currentQueue,
tornadoServiceFee: status.tornadoServiceFee,
} as RelayerInfo;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (err: any) {
if (debugRelayer) {
throw err;
}
return {
hostname,
relayerAddress,
errorMessage: err.message,
} as RelayerError;
}
} else {
if (debugRelayer) {
const errMsg = `Relayer ${hostname} condition not met`;
throw new Error(errMsg);
}
return {
async askRelayerStatus({
hostname,
url,
relayerAddress,
errorMessage: `Relayer ${hostname} condition not met`,
};
}
}
async getValidRelayers(
// this should be ascending order of events
relayers: RelayerParams[],
subdomains: string[],
debugRelayer: boolean = false,
): Promise<{
validRelayers: RelayerInfo[];
invalidRelayers: RelayerError[];
}> {
const relayersSet = new Set();
const uniqueRelayers = relayers.reverse().filter(({ ensName }) => {
if (!relayersSet.has(ensName)) {
relayersSet.add(ensName);
return true;
}
return false;
});
const relayerNameHashes = uniqueRelayers.map((r) => namehash(r.ensName));
const relayersData = await this.Aggregator.relayersData.staticCall(relayerNameHashes, subdomains);
const invalidRelayers: RelayerError[] = [];
const validRelayers = (
await Promise.all(
relayersData.map((curr, index) => this.filterRelayer(curr, uniqueRelayers[index], subdomains, debugRelayer)),
)
).filter((r) => {
if ((r as RelayerError).errorMessage) {
invalidRelayers.push(r);
return false;
}
return true;
}) as RelayerInfo[];
return {
validRelayers,
invalidRelayers,
};
}
pickWeightedRandomRelayer(relayers: RelayerInfo[]) {
return pickWeightedRandomRelayer(relayers, this.netId);
}
async tornadoWithdraw({ contract, proof, args }: RelayerClientWithdraw) {
const { url } = this.selectedRelayer as Relayer;
const withdrawResponse = (await fetchData(`${url}v1/tornadoWithdraw`, {
...this.fetchDataOptions,
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
contract,
proof,
args,
}),
})) as RelayerTornadoWithdraw;
const { id, error } = withdrawResponse;
if (error) {
throw new Error(error);
}
let relayerStatus: string | undefined;
const jobUrl = `${url}v1/jobs/${id}`;
console.log(`Job submitted: ${jobUrl}\n`);
while (!relayerStatus || !['FAILED', 'CONFIRMED'].includes(relayerStatus)) {
const jobResponse = await fetchData(jobUrl, {
...this.fetchDataOptions,
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
if (jobResponse.error) {
throw new Error(error);
}
const jobValidator = ajv.compile(jobsSchema);
if (!jobValidator(jobResponse)) {
const errMsg = `${jobUrl} has an invalid job response`;
throw new Error(errMsg);
}
const { status, txHash, confirmations, failedReason } = jobResponse as unknown as RelayerTornadoJobs;
if (relayerStatus !== status) {
if (status === 'FAILED') {
const errMsg = `Job ${status}: ${jobUrl} failed reason: ${failedReason}`;
throw new Error(errMsg);
} else if (status === 'SENT') {
console.log(`Job ${status}: ${jobUrl}, txhash: ${txHash}\n`);
} else if (status === 'MINED') {
console.log(`Job ${status}: ${jobUrl}, txhash: ${txHash}, confirmations: ${confirmations}\n`);
} else if (status === 'CONFIRMED') {
console.log(`Job ${status}: ${jobUrl}, txhash: ${txHash}, confirmations: ${confirmations}\n`);
}: {
hostname?: string;
// optional url if entered manually
url?: string;
// relayerAddress from registry contract to prevent cheating
relayerAddress?: string;
}): Promise<RelayerStatus> {
if (!url && hostname) {
url = `https://${!hostname.endsWith('/') ? hostname + '/' : hostname}`;
} else if (url && !url.endsWith('/')) {
url += '/';
} else {
console.log(`Job ${status}: ${jobUrl}\n`);
url = '';
}
relayerStatus = status;
}
const rawStatus = (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;
await sleep(3000);
const statusValidator = ajv.compile(getStatusSchema(this.netId, this.config, this.tovarish));
if (!statusValidator(rawStatus)) {
throw new Error('Invalid status schema');
}
const status = {
...rawStatus,
url,
} as RelayerStatus;
if (status.currentQueue > 5) {
throw new Error('Withdrawal queue is overloaded');
}
if (status.netId !== this.netId) {
throw new Error('This relayer serves a different network');
}
if (relayerAddress && this.netId === NetId.MAINNET && status.rewardAccount !== relayerAddress) {
throw new Error('The Relayer reward address must match registered address');
}
return status;
}
async filterRelayer(relayer: CachedRelayerInfo): Promise<RelayerInfo | RelayerError | undefined> {
const hostname = relayer.hostnames[this.netId];
const { ensName, relayerAddress } = relayer;
if (!hostname) {
return;
}
try {
const status = await this.askRelayerStatus({
hostname,
relayerAddress,
});
return {
netId: status.netId,
url: status.url,
hostname,
ensName,
relayerAddress,
rewardAccount: getAddress(status.rewardAccount),
instances: getSupportedInstances(status.instances),
stakeBalance: relayer.stakeBalance,
gasPrice: status.gasPrices?.fast,
ethPrices: status.ethPrices,
currentQueue: status.currentQueue,
tornadoServiceFee: status.tornadoServiceFee,
} as RelayerInfo;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (err: any) {
return {
hostname,
relayerAddress,
errorMessage: err.message,
hasError: true,
} as RelayerError;
}
}
async getValidRelayers(relayers: CachedRelayerInfo[]): Promise<{
validRelayers: RelayerInfo[];
invalidRelayers: RelayerError[];
}> {
const invalidRelayers: RelayerError[] = [];
const validRelayers = (await Promise.all(relayers.map((relayer) => this.filterRelayer(relayer)))).filter(
(r) => {
if (!r) {
return false;
}
if ((r as RelayerError).hasError) {
invalidRelayers.push(r as RelayerError);
return false;
}
return true;
},
) as RelayerInfo[];
return {
validRelayers,
invalidRelayers,
};
}
pickWeightedRandomRelayer(relayers: RelayerInfo[]) {
return pickWeightedRandomRelayer(relayers);
}
async tornadoWithdraw(
{ contract, proof, args }: TornadoWithdrawParams,
callback?: (jobResp: RelayerTornadoWithdraw | RelayerTornadoJobs) => void,
) {
const { url } = this.selectedRelayer as RelayerInfo;
/**
* Request new job
*/
const withdrawResponse = (await fetchData(`${url}v1/tornadoWithdraw`, {
...this.fetchDataOptions,
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
contract,
proof,
args,
}),
})) as RelayerTornadoWithdraw;
const { id, error } = withdrawResponse;
if (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;
const jobUrl = `${url}v1/jobs/${id}`;
console.log(`Job submitted: ${jobUrl}\n`);
while (!relayerStatus || !['FAILED', 'CONFIRMED'].includes(relayerStatus)) {
const jobResponse = await fetchData(jobUrl, {
...this.fetchDataOptions,
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
if (jobResponse.error) {
throw new Error(error);
}
const jobValidator = ajv.compile(jobsSchema);
if (!jobValidator(jobResponse)) {
const errMsg = `${jobUrl} has an invalid job response`;
throw new Error(errMsg);
}
const { status, txHash, confirmations, failedReason } = jobResponse as unknown as RelayerTornadoJobs;
if (relayerStatus !== status) {
if (status === 'FAILED') {
const errMsg = `Job ${status}: ${jobUrl} failed reason: ${failedReason}`;
throw new Error(errMsg);
} else if (status === 'SENT') {
console.log(`Job ${status}: ${jobUrl}, txhash: ${txHash}\n`);
} else if (status === 'MINED') {
console.log(`Job ${status}: ${jobUrl}, txhash: ${txHash}, confirmations: ${confirmations}\n`);
} else if (status === 'CONFIRMED') {
console.log(`Job ${status}: ${jobUrl}, txhash: ${txHash}, confirmations: ${confirmations}\n`);
} else {
console.log(`Job ${status}: ${jobUrl}\n`);
}
relayerStatus = status;
if (typeof callback === 'function') {
callback(jobResponse as unknown as RelayerTornadoJobs);
}
}
await sleep(3000);
}
}
}
}

31
src/schemas/ajv.ts Normal file
View File

@@ -0,0 +1,31 @@
import Ajv from 'ajv';
import { BigNumberish, isAddress } from 'ethers';
export const ajv = new Ajv({ allErrors: true });
ajv.addKeyword({
keyword: 'BN',
// eslint-disable-next-line @typescript-eslint/no-explicit-any
validate: (schema: any, data: BigNumberish) => {
try {
BigInt(data);
return true;
} catch {
return false;
}
},
errors: true,
});
ajv.addKeyword({
keyword: 'isAddress',
// eslint-disable-next-line @typescript-eslint/no-explicit-any
validate: (schema: any, data: string) => {
try {
return isAddress(data);
} catch {
return false;
}
},
errors: true,
});

321
src/schemas/events.ts Normal file
View File

@@ -0,0 +1,321 @@
import { ajv } from './ajv';
import { addressSchemaType, bnSchemaType, bytes32SchemaType } from './types';
const baseEventsSchemaProperty = {
blockNumber: {
type: 'number',
},
logIndex: {
type: 'number',
},
transactionHash: bytes32SchemaType,
} as const;
const baseEventsSchemaRequired = Object.keys(baseEventsSchemaProperty) as string[];
export const governanceEventsSchema = {
type: 'array',
items: {
anyOf: [
{
type: 'object',
properties: {
...baseEventsSchemaProperty,
event: { type: 'string' },
id: { type: 'number' },
proposer: addressSchemaType,
target: addressSchemaType,
startTime: { type: 'number' },
endTime: { type: 'number' },
description: { type: 'string' },
},
required: [
...baseEventsSchemaRequired,
'event',
'id',
'proposer',
'target',
'startTime',
'endTime',
'description',
],
additionalProperties: false,
},
{
type: 'object',
properties: {
...baseEventsSchemaProperty,
event: { type: 'string' },
proposalId: { type: 'number' },
voter: addressSchemaType,
support: { type: 'boolean' },
votes: { type: 'string' },
from: addressSchemaType,
input: { type: 'string' },
},
required: [
...baseEventsSchemaRequired,
'event',
'proposalId',
'voter',
'support',
'votes',
'from',
'input',
],
additionalProperties: false,
},
{
type: 'object',
properties: {
...baseEventsSchemaProperty,
event: { type: 'string' },
account: addressSchemaType,
delegateTo: addressSchemaType,
},
required: [...baseEventsSchemaRequired, 'account', 'delegateTo'],
additionalProperties: false,
},
{
type: 'object',
properties: {
...baseEventsSchemaProperty,
event: { type: 'string' },
account: addressSchemaType,
delegateFrom: addressSchemaType,
},
required: [...baseEventsSchemaRequired, 'account', 'delegateFrom'],
additionalProperties: false,
},
],
},
} as const;
export const relayerRegistryEventsSchema = {
type: 'array',
items: {
anyOf: [
// RelayerRegisteredEvents
{
type: 'object',
properties: {
...baseEventsSchemaProperty,
event: { type: 'string' },
ensName: { type: 'string' },
relayerAddress: addressSchemaType,
ensHash: { type: 'string' },
stakedAmount: { type: 'string' },
},
required: [
...baseEventsSchemaRequired,
'event',
'ensName',
'relayerAddress',
'ensHash',
'stakedAmount',
],
additionalProperties: false,
},
// RelayerUnregisteredEvents
{
type: 'object',
properties: {
...baseEventsSchemaProperty,
event: { type: 'string' },
relayerAddress: addressSchemaType,
},
required: [...baseEventsSchemaRequired, 'event', 'relayerAddress'],
additionalProperties: false,
},
// WorkerRegisteredEvents & WorkerUnregisteredEvents
{
type: 'object',
properties: {
...baseEventsSchemaProperty,
event: { type: 'string' },
relayerAddress: addressSchemaType,
workerAddress: addressSchemaType,
},
required: [...baseEventsSchemaRequired, 'event', 'relayerAddress', 'workerAddress'],
additionalProperties: false,
},
],
},
} as const;
export const stakeBurnedEventsSchema = {
type: 'array',
items: {
type: 'object',
properties: {
...baseEventsSchemaProperty,
relayerAddress: addressSchemaType,
amountBurned: bnSchemaType,
instanceAddress: addressSchemaType,
gasFee: bnSchemaType,
relayerFee: bnSchemaType,
timestamp: { type: 'number' },
},
required: [
...baseEventsSchemaRequired,
'relayerAddress',
'amountBurned',
'instanceAddress',
'gasFee',
'relayerFee',
'timestamp',
],
additionalProperties: false,
},
} as const;
export const depositsEventsSchema = {
type: 'array',
items: {
type: 'object',
properties: {
...baseEventsSchemaProperty,
commitment: bytes32SchemaType,
leafIndex: { type: 'number' },
timestamp: { type: 'number' },
from: addressSchemaType,
},
required: [...baseEventsSchemaRequired, 'commitment', 'leafIndex', 'timestamp', 'from'],
additionalProperties: false,
},
} as const;
export const withdrawalsEventsSchema = {
type: 'array',
items: {
type: 'object',
properties: {
...baseEventsSchemaProperty,
nullifierHash: bytes32SchemaType,
to: addressSchemaType,
fee: bnSchemaType,
timestamp: { type: 'number' },
},
required: [...baseEventsSchemaRequired, 'nullifierHash', 'to', 'fee', 'timestamp'],
additionalProperties: false,
},
} as const;
export const tornadoEventsSchema = {
type: 'array',
items: {
anyOf: [
// depositsEvents
{
type: 'object',
properties: {
...baseEventsSchemaProperty,
event: { type: 'string' },
instanceAddress: { type: 'string' },
commitment: bytes32SchemaType,
leafIndex: { type: 'number' },
timestamp: { type: 'number' },
from: addressSchemaType,
},
required: [
...baseEventsSchemaRequired,
'event',
'instanceAddress',
'commitment',
'leafIndex',
'timestamp',
'from',
],
additionalProperties: false,
},
// withdrawalEvents
{
type: 'object',
properties: {
...baseEventsSchemaProperty,
event: { type: 'string' },
instanceAddress: { type: 'string' },
nullifierHash: bytes32SchemaType,
to: addressSchemaType,
relayerAddress: addressSchemaType,
fee: bnSchemaType,
timestamp: { type: 'number' },
},
required: [
...baseEventsSchemaRequired,
'event',
'instanceAddress',
'nullifierHash',
'to',
'relayerAddress',
'fee',
'timestamp',
],
additionalProperties: false,
},
],
},
} as const;
export const echoEventsSchema = {
type: 'array',
items: {
type: 'object',
properties: {
...baseEventsSchemaProperty,
address: addressSchemaType,
encryptedAccount: { type: 'string' },
},
required: [...baseEventsSchemaRequired, 'address', 'encryptedAccount'],
additionalProperties: false,
},
} as const;
export const encryptedNotesSchema = {
type: 'array',
items: {
type: 'object',
properties: {
...baseEventsSchemaProperty,
encryptedNote: { type: 'string' },
},
required: [...baseEventsSchemaRequired, 'encryptedNote'],
additionalProperties: false,
},
} as const;
export function getEventsSchemaValidator(type: string) {
if (type === 'tornado') {
return ajv.compile(tornadoEventsSchema);
}
if (type === 'deposit') {
return ajv.compile(depositsEventsSchema);
}
if (type === 'withdrawal') {
return ajv.compile(withdrawalsEventsSchema);
}
if (type === 'governance') {
return ajv.compile(governanceEventsSchema);
}
if (type === 'registry') {
return ajv.compile(relayerRegistryEventsSchema);
}
if (type === 'revenue') {
return ajv.compile(stakeBurnedEventsSchema);
}
if (type === 'echo') {
return ajv.compile(echoEventsSchema);
}
if (type === 'encrypted_notes') {
return ajv.compile(encryptedNotesSchema);
}
throw new Error('Unsupported event type for schema validation');
}

View File

@@ -1,21 +1,5 @@
import Ajv from 'ajv';
import type { BigNumberish } from 'ethers';
export const ajv = new Ajv({ allErrors: true });
ajv.addKeyword({
keyword: 'BN',
// eslint-disable-next-line @typescript-eslint/no-explicit-any
validate: (schema: any, data: BigNumberish) => {
try {
BigInt(data);
return true;
} catch (e) {
return false;
}
},
errors: true,
});
export * from './ajv';
export * from './events';
export * from './status';
export * from './jobs';
export * from './types';

View File

@@ -1,59 +1,64 @@
export type jobsSchema = {
type: string;
properties: {
error: {
type: string;
export interface jobsSchema {
type: string;
properties: {
error: {
type: string;
};
id: {
type: string;
};
type: {
type: string;
};
status: {
type: string;
};
contract: {
type: string;
};
proof: {
type: string;
};
args: {
type: string;
items: {
type: string;
};
};
txHash: {
type: string;
};
confirmations: {
type: string;
};
failedReason: {
type: string;
};
};
id: {
type: string;
};
type: {
type: string;
};
status: {
type: string;
};
contract: {
type: string;
};
proof: {
type: string;
};
args: {
type: string;
items: {
type: string;
};
};
txHash: {
type: string;
};
confirmations: {
type: string;
};
failedReason: {
type: string;
};
};
required: string[];
};
required: string[];
}
export const jobsSchema: jobsSchema = {
type: 'object',
properties: {
error: { type: 'string' },
id: { type: 'string' },
type: { type: 'string' },
status: { type: 'string' },
contract: { type: 'string' },
proof: { type: 'string' },
args: {
type: 'array',
items: { type: 'string' },
type: 'object',
properties: {
error: { type: 'string' },
id: { type: 'string' },
type: { type: 'string' },
status: { type: 'string' },
contract: { type: 'string' },
proof: { type: 'string' },
args: {
type: 'array',
items: { type: 'string' },
},
txHash: { type: 'string' },
confirmations: { type: 'number' },
failedReason: { type: 'string' },
},
txHash: { type: 'string' },
confirmations: { type: 'number' },
failedReason: { type: 'string' },
},
required: ['id', 'status'],
required: ['id', 'status'],
};
export const jobRequestSchema: jobsSchema = {
...jobsSchema,
required: ['id'],
};

View File

@@ -1,181 +1,221 @@
import { Config, NetId, NetIdType } from '../networkConfig';
import { addressSchemaType, bnSchemaType } from '.';
export type statusInstanceType = {
type: string;
properties: {
instanceAddress: {
type: string;
properties: {
[key in string]: typeof addressType;
};
required: string[];
};
tokenAddress?: typeof addressType;
symbol?: { enum: string[] };
decimals: { enum: number[] };
};
required: string[];
};
export type statusInstancesType = {
type: string;
properties: {
[key in string]: statusInstanceType;
};
required: string[];
};
export type statusEthPricesType = {
type: string;
properties: {
[key in string]: typeof bnType;
};
required?: string[];
};
export type statusSchema = {
type: string;
properties: {
rewardAccount: typeof addressType;
instances?: statusInstancesType;
gasPrices: {
type: string;
properties: {
[key in string]: {
type: string;
export interface statusInstanceType {
type: string;
properties: {
instanceAddress: {
type: string;
properties: {
[key in string]: typeof addressSchemaType;
};
required: string[];
};
};
required: string[];
tokenAddress?: typeof addressSchemaType;
symbol?: { enum: string[] };
decimals: { enum: number[] };
};
netId: {
type: string;
};
ethPrices?: statusEthPricesType;
tornadoServiceFee?: {
type: string;
maximum: number;
minimum: number;
};
latestBlock?: {
type: string;
};
version: {
type: string;
};
health: {
type: string;
properties: {
status: { const: string };
error: { type: string };
};
required: string[];
};
currentQueue: {
type: string;
};
};
required: string[];
};
required: string[];
}
const addressType = { type: 'string', pattern: '^0x[a-fA-F0-9]{40}$' };
export interface statusInstancesType {
type: string;
properties: {
[key in string]: statusInstanceType;
};
required: string[];
}
const bnType = { type: 'string', BN: true };
export interface statusEthPricesType {
type: string;
properties: {
[key in string]: typeof bnSchemaType;
};
required?: string[];
}
export interface statusSchema {
type: string;
properties: {
rewardAccount: typeof addressSchemaType;
instances?: statusInstancesType;
gasPrices: {
type: string;
properties: {
[key in string]: {
type: string;
};
};
required: string[];
};
netId: {
type: string;
};
ethPrices?: statusEthPricesType;
tornadoServiceFee?: {
type: string;
maximum: number;
minimum: number;
};
latestBlock: {
type: string;
};
latestBalance: {
type: string;
BN: boolean;
};
version: {
type: string;
};
health: {
type: string;
properties: {
status: { const: string };
error: { type: string };
};
required: string[];
};
syncStatus: {
type: string;
properties: {
events: { type: string };
tokenPrice: { type: string };
gasPrice: { type: string };
};
required: string[];
};
onSyncEvents: { type: string };
currentQueue: {
type: string;
};
};
required: string[];
}
const statusSchema: statusSchema = {
type: 'object',
properties: {
rewardAccount: addressType,
gasPrices: {
type: 'object',
properties: {
fast: { type: 'number' },
additionalProperties: { type: 'number' },
},
required: ['fast'],
type: 'object',
properties: {
rewardAccount: addressSchemaType,
gasPrices: {
type: 'object',
properties: {
fast: { type: 'number' },
additionalProperties: { type: 'number' },
},
required: ['fast'],
},
netId: { type: 'integer' },
tornadoServiceFee: { type: 'number', maximum: 20, minimum: 0 },
latestBlock: { type: 'number' },
latestBalance: bnSchemaType,
version: { type: 'string' },
health: {
type: 'object',
properties: {
status: { const: 'true' },
error: { type: 'string' },
},
required: ['status'],
},
syncStatus: {
type: 'object',
properties: {
events: { type: 'boolean' },
tokenPrice: { type: 'boolean' },
gasPrice: { type: 'boolean' },
},
required: ['events', 'tokenPrice', 'gasPrice'],
},
onSyncEvents: { type: 'boolean' },
currentQueue: { type: 'number' },
},
netId: { type: 'integer' },
tornadoServiceFee: { type: 'number', maximum: 20, minimum: 0 },
latestBlock: { type: 'number' },
version: { type: 'string' },
health: {
type: 'object',
properties: {
status: { const: 'true' },
error: { type: 'string' },
},
required: ['status'],
},
currentQueue: { type: 'number' },
},
required: ['rewardAccount', 'instances', 'netId', 'tornadoServiceFee', 'version', 'health'],
required: ['rewardAccount', 'instances', 'netId', 'tornadoServiceFee', 'version', 'health', 'currentQueue'],
};
export function getStatusSchema(netId: NetIdType, config: Config) {
const { tokens, optionalTokens = [], nativeCurrency } = config;
export function getStatusSchema(netId: NetIdType, config: Config, tovarish: boolean) {
const { tokens, optionalTokens, disabledTokens, nativeCurrency } = config;
// deep copy schema
const schema = JSON.parse(JSON.stringify(statusSchema)) as statusSchema;
// deep copy schema
const schema = JSON.parse(JSON.stringify(statusSchema)) as statusSchema;
const instances = Object.keys(tokens).reduce(
(acc: statusInstancesType, token) => {
const { instanceAddress, tokenAddress, symbol, decimals, optionalInstances = [] } = tokens[token];
const amounts = Object.keys(instanceAddress);
const instances = Object.keys(tokens).reduce(
(acc: statusInstancesType, token) => {
const { instanceAddress, tokenAddress, symbol, decimals, optionalInstances = [] } = tokens[token];
const amounts = Object.keys(instanceAddress);
const instanceProperties: statusInstanceType = {
type: 'object',
properties: {
instanceAddress: {
type: 'object',
properties: amounts.reduce((acc: { [key in string]: typeof addressType }, cur) => {
acc[cur] = addressType;
return acc;
}, {}),
required: amounts.filter((amount) => !optionalInstances.includes(amount)),
},
decimals: { enum: [decimals] },
const instanceProperties: statusInstanceType = {
type: 'object',
properties: {
instanceAddress: {
type: 'object',
properties: amounts.reduce(
(
acc: {
[key in string]: typeof addressSchemaType;
},
cur,
) => {
acc[cur] = addressSchemaType;
return acc;
},
{},
),
required: amounts.filter((amount) => !optionalInstances.includes(amount)),
},
decimals: { enum: [decimals] },
},
required: ['instanceAddress', 'decimals'].concat(
tokenAddress ? ['tokenAddress'] : [],
symbol ? ['symbol'] : [],
),
};
if (tokenAddress) {
instanceProperties.properties.tokenAddress = addressSchemaType;
}
if (symbol) {
instanceProperties.properties.symbol = { enum: [symbol] };
}
acc.properties[token] = instanceProperties;
if (!optionalTokens?.includes(token) && !disabledTokens?.includes(token)) {
acc.required.push(token);
}
return acc;
},
required: ['instanceAddress', 'decimals'].concat(
tokenAddress ? ['tokenAddress'] : [],
symbol ? ['symbol'] : [],
),
};
{
type: 'object',
properties: {},
required: [],
},
);
if (tokenAddress) {
instanceProperties.properties.tokenAddress = addressType;
}
if (symbol) {
instanceProperties.properties.symbol = { enum: [symbol] };
}
schema.properties.instances = instances;
acc.properties[token] = instanceProperties;
if (!optionalTokens.includes(token)) {
acc.required.push(token);
}
return acc;
},
{
type: 'object',
properties: {},
required: [],
},
);
const _tokens = Object.keys(tokens).filter(
(t) => t !== nativeCurrency && !config.optionalTokens?.includes(t) && !config.disabledTokens?.includes(t),
);
schema.properties.instances = instances;
if (netId === NetId.MAINNET) {
_tokens.push('torn');
}
if (netId === NetId.MAINNET) {
const _tokens = Object.keys(tokens).filter((t) => t !== nativeCurrency);
if (_tokens.length) {
const ethPrices: statusEthPricesType = {
type: 'object',
properties: _tokens.reduce((acc: { [key in string]: typeof bnSchemaType }, token: string) => {
acc[token] = bnSchemaType;
return acc;
}, {}),
required: _tokens,
};
schema.properties.ethPrices = ethPrices;
schema.required.push('ethPrices');
}
const ethPrices: statusEthPricesType = {
type: 'object',
properties: _tokens.reduce((acc: { [key in string]: typeof bnType }, token: string) => {
acc[token] = bnType;
return acc;
}, {}),
// required: _tokens
};
schema.properties.ethPrices = ethPrices;
// schema.required.push('ethPrices')
}
if (tovarish) {
schema.required.push('gasPrices', 'latestBlock', 'latestBalance', 'syncStatus', 'onSyncEvents');
}
return schema;
return schema;
}

15
src/schemas/types.ts Normal file
View File

@@ -0,0 +1,15 @@
export const addressSchemaType = {
type: 'string',
pattern: '^0x[a-fA-F0-9]{40}$',
isAddress: true,
} as const;
export const bnSchemaType = { type: 'string', BN: true } as const;
export const proofSchemaType = {
type: 'string',
pattern: '^0x[a-fA-F0-9]{512}$',
} as const;
export const bytes32SchemaType = {
type: 'string',
pattern: '^0x[a-fA-F0-9]{64}$',
} as const;
export const bytes32BNSchemaType = { ...bytes32SchemaType, BN: true } as const;

View File

@@ -4,87 +4,87 @@ import { chunk } from './utils';
import { Call3, multicall } from './multicall';
export interface tokenBalances {
address: string;
name: string;
symbol: string;
decimals: number;
balance: bigint;
address: string;
name: string;
symbol: string;
decimals: number;
balance: bigint;
}
export async function getTokenBalances({
provider,
Multicall,
currencyName,
userAddress,
tokenAddresses = [],
provider,
Multicall,
currencyName,
userAddress,
tokenAddresses = [],
}: {
provider: Provider;
Multicall: Multicall;
currencyName: string;
userAddress: string;
tokenAddresses: string[];
provider: Provider;
Multicall: Multicall;
currencyName: string;
userAddress: string;
tokenAddresses: string[];
}): Promise<tokenBalances[]> {
const tokenCalls = tokenAddresses
.map((tokenAddress) => {
const Token = ERC20__factory.connect(tokenAddress, provider);
const tokenCalls = tokenAddresses
.map((tokenAddress) => {
const Token = ERC20__factory.connect(tokenAddress, provider);
return [
return [
{
contract: Token,
name: 'balanceOf',
params: [userAddress],
},
{
contract: Token,
name: 'name',
},
{
contract: Token,
name: 'symbol',
},
{
contract: Token,
name: 'decimals',
},
];
})
.flat() as Call3[];
const multicallResults = await multicall(Multicall, [
{
contract: Token,
name: 'balanceOf',
params: [userAddress],
contract: Multicall,
name: 'getEthBalance',
params: [userAddress],
},
...(tokenCalls.length ? tokenCalls : []),
]);
const ethResults = multicallResults[0];
const tokenResults = multicallResults.slice(1).length
? chunk(multicallResults.slice(1), tokenCalls.length / tokenAddresses.length)
: [];
const tokenBalances = tokenResults.map((tokenResult, index) => {
const [tokenBalance, tokenName, tokenSymbol, tokenDecimals] = tokenResult;
const tokenAddress = tokenAddresses[index];
return {
address: tokenAddress,
name: tokenName,
symbol: tokenSymbol,
decimals: Number(tokenDecimals),
balance: tokenBalance,
};
});
return [
{
contract: Token,
name: 'name',
address: ZeroAddress,
name: currencyName,
symbol: currencyName,
decimals: 18,
balance: ethResults,
},
{
contract: Token,
name: 'symbol',
},
{
contract: Token,
name: 'decimals',
},
];
})
.flat() as Call3[];
const multicallResults = await multicall(Multicall, [
{
contract: Multicall,
name: 'getEthBalance',
params: [userAddress],
},
...(tokenCalls.length ? tokenCalls : []),
]);
const ethResults = multicallResults[0];
const tokenResults = multicallResults.slice(1).length
? chunk(multicallResults.slice(1), tokenCalls.length / tokenAddresses.length)
: [];
const tokenBalances = tokenResults.map((tokenResult, index) => {
const [tokenBalance, tokenName, tokenSymbol, tokenDecimals] = tokenResult;
const tokenAddress = tokenAddresses[index];
return {
address: tokenAddress,
name: tokenName,
symbol: tokenSymbol,
decimals: Number(tokenDecimals),
balance: tokenBalance,
};
});
return [
{
address: ZeroAddress,
name: currencyName,
symbol: currencyName,
decimals: 18,
balance: ethResults,
},
...tokenBalances,
];
...tokenBalances,
];
}

399
src/tovarishClient.ts Normal file
View File

@@ -0,0 +1,399 @@
import { getAddress } from 'ethers';
import {
RelayerClient,
RelayerClientConstructor,
RelayerError,
RelayerInfo,
RelayerStatus,
getSupportedInstances,
} from './relayerClient';
import { fetchData } from './providers';
import { CachedRelayerInfo, MinimalEvents } from './events';
import { ajv, getEventsSchemaValidator, getStatusSchema } from './schemas';
import { enabledChains, getConfig, NetId, NetIdType } from './networkConfig';
// Return no more than 5K events per query
export const MAX_TOVARISH_EVENTS = 5000;
export interface EventsStatus {
events: number;
lastBlock: number;
}
export interface TovarishEventsStatus {
governance?: EventsStatus;
registry?: EventsStatus;
revenue?: EventsStatus;
echo: EventsStatus;
encrypted_notes: EventsStatus;
tornado: EventsStatus;
}
export interface TovarishSyncStatus {
events: boolean;
tokenPrice: boolean;
gasPrice: boolean;
}
// Expected response from /status endpoint
export interface TovarishStatus extends RelayerStatus {
latestBalance: string;
events: TovarishEventsStatus;
syncStatus: TovarishSyncStatus;
onSyncEvents: boolean;
}
// Formatted TovarishStatus for Frontend usage
export interface TovarishInfo extends RelayerInfo {
latestBlock: number;
latestBalance: string;
version: string;
events: TovarishEventsStatus;
syncStatus: TovarishSyncStatus;
}
// Query input for TovarishEvents
export interface TovarishEventsQuery {
type: string;
currency?: string;
amount?: string;
fromBlock: number;
recent?: boolean;
}
export interface BaseTovarishEvents<T> {
events: T[];
lastSyncBlock: number;
}
export class TovarishClient extends RelayerClient {
declare selectedRelayer?: TovarishInfo;
constructor(clientConstructor: RelayerClientConstructor) {
super(clientConstructor);
this.tovarish = true;
}
async askRelayerStatus({
hostname,
url,
relayerAddress,
}: {
hostname?: string;
// optional url if entered manually
url?: string;
// relayerAddress from registry contract to prevent cheating
relayerAddress?: string;
}): Promise<TovarishStatus> {
const status = (await super.askRelayerStatus({
hostname,
url,
relayerAddress,
})) as TovarishStatus;
if (!status.version.includes('tovarish')) {
throw new Error('Not a tovarish relayer!');
}
return status;
}
/**
* 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);
const statusValidator = ajv.compile(
getStatusSchema(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(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> {
const { ensName, relayerAddress, tovarishHost, tovarishNetworks } = relayer;
if (!tovarishHost || !tovarishNetworks?.includes(this.netId)) {
return;
}
const hostname = `${tovarishHost}/${this.netId}`;
try {
const status = await this.askRelayerStatus({
hostname,
relayerAddress,
});
return {
netId: status.netId,
url: status.url,
hostname,
ensName,
relayerAddress,
rewardAccount: getAddress(status.rewardAccount),
instances: getSupportedInstances(status.instances),
stakeBalance: relayer.stakeBalance,
gasPrice: status.gasPrices?.fast,
ethPrices: status.ethPrices,
currentQueue: status.currentQueue,
tornadoServiceFee: status.tornadoServiceFee,
// Additional fields for tovarish relayer
latestBlock: Number(status.latestBlock),
latestBalance: status.latestBalance,
version: status.version,
events: status.events,
syncStatus: status.syncStatus,
} as TovarishInfo;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (err: any) {
return {
hostname,
relayerAddress,
errorMessage: err.message,
hasError: true,
} as RelayerError;
}
}
async getValidRelayers(relayers: CachedRelayerInfo[]): Promise<{
validRelayers: TovarishInfo[];
invalidRelayers: RelayerError[];
}> {
const invalidRelayers: RelayerError[] = [];
const validRelayers = (await Promise.all(relayers.map((relayer) => this.filterRelayer(relayer)))).filter(
(r) => {
if (!r) {
return false;
}
if ((r as RelayerError).hasError) {
invalidRelayers.push(r as RelayerError);
return false;
}
return true;
},
) as TovarishInfo[];
return {
validRelayers,
invalidRelayers,
};
}
async 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>({
type,
currency,
amount,
fromBlock,
recent,
}: TovarishEventsQuery): Promise<BaseTovarishEvents<T>> {
const url = `${this.selectedRelayer?.url}events`;
const schemaValidator = getEventsSchemaValidator(type);
try {
const events = [];
let lastSyncBlock = fromBlock;
// eslint-disable-next-line no-constant-condition
while (true) {
// eslint-disable-next-line prefer-const
let { events: fetchedEvents, lastSyncBlock: currentBlock } = (await fetchData(url, {
...this.fetchDataOptions,
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
type,
currency,
amount,
fromBlock,
recent,
}),
})) as BaseTovarishEvents<T>;
if (!schemaValidator(fetchedEvents)) {
const errMsg = `Schema validation failed for ${type} events`;
throw new Error(errMsg);
}
if (recent) {
return {
events: fetchedEvents,
lastSyncBlock: currentBlock,
};
}
lastSyncBlock = currentBlock;
if (!Array.isArray(fetchedEvents) || !fetchedEvents.length) {
break;
}
fetchedEvents = fetchedEvents.sort((a, b) => {
if (a.blockNumber === b.blockNumber) {
return a.logIndex - b.logIndex;
}
return a.blockNumber - b.blockNumber;
});
const [lastEvent] = fetchedEvents.slice(-1);
if (fetchedEvents.length < MAX_TOVARISH_EVENTS - 100) {
events.push(...fetchedEvents);
break;
}
fetchedEvents = fetchedEvents.filter((e) => e.blockNumber !== lastEvent.blockNumber);
fromBlock = Number(lastEvent.blockNumber);
events.push(...fetchedEvents);
}
return {
events,
lastSyncBlock,
};
} catch (err) {
console.log('Error from TovarishClient events endpoint');
console.log(err);
return {
events: [],
lastSyncBlock: fromBlock,
};
}
}
}

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More