2023.04.20: Check HISTORY.md for more info

Signed-off-by: T-Hax <>
This commit is contained in:
T-Hax 2023-04-19 17:01:40 +00:00
parent d83dcd8112
commit 4b661dd3e6
15 changed files with 459 additions and 327 deletions

@ -1,5 +1,16 @@
# History
### 2023.04.20 (2023-04-20)
Did:
* Syncing is now stable.
* Reorganized some stuff including resources.
Next:
* Still testing withdraws, will do some relayer and then monorepo :] (finally excited about something again)
### 2023.04.18 (2023-04-18)
Did:

@ -10,7 +10,7 @@
"zk"
],
"private": false,
"version": "2023.04.18",
"version": "2023.04.20",
"engines": {
"node": "^18"
},

@ -22,7 +22,7 @@ import { BaseContract, BigNumber, ContractTransaction, providers, Signer, VoidSi
import { randomBytes } from 'crypto'
// Local modules
import { OnchainData } from 'lib/data'
import { Onchain } from 'lib/data'
import { ErrorUtils, HexUtils } from 'lib/utils'
// We use a vanilla provider here, but in reality we will probably
@ -52,7 +52,7 @@ export class Chain {
}
async getChainSymbol(): Promise<string> {
if (!this.symbol) this.symbol = await OnchainData.getNetworkSymbol(String(await this.getChainId()))
if (!this.symbol) this.symbol = await Onchain.getNetworkSymbol(String(await this.getChainId()))
return this.symbol
}
@ -94,12 +94,12 @@ export class Chain {
): Promise<TransactionRequest> {
if (callStruct[0].value)
return await Multicall3Contract__factory.connect(
await OnchainData.getMulticall3Address(String(this.chainId)),
await Onchain.getMulticall3Address(String(this.chainId)),
this.provider
).populateTransaction.aggregate3Value(callStruct as Array<Multicall3.Call3ValueStruct>)
return await Multicall3Contract__factory.connect(
await OnchainData.getMulticall3Address(String(this.chainId)),
await Onchain.getMulticall3Address(String(this.chainId)),
this.provider
).populateTransaction.aggregate3(callStruct)
}
@ -110,12 +110,12 @@ export class Chain {
if (this.signer)
if (callStruct[0].value)
return await Multicall3Contract__factory.connect(
await OnchainData.getMulticall3Address(String(this.chainId)),
await Onchain.getMulticall3Address(String(this.chainId)),
this.signer
).aggregate3Value(callStruct as Array<Multicall3.Call3ValueStruct>)
else {
return await Multicall3Contract__factory.connect(
await OnchainData.getMulticall3Address(String(this.chainId)),
await Onchain.getMulticall3Address(String(this.chainId)),
this.provider
).aggregate3(callStruct)
}
@ -156,11 +156,7 @@ export namespace Contracts {
if (!contractMap.has(key)) {
contractMap.set(
key,
_getContract<TornadoProxy>(
'TornadoProxy',
await OnchainData.getProxyAddress(network),
signerOrProvider
)
_getContract<TornadoProxy>('TornadoProxy', await Onchain.getProxyAddress(network), signerOrProvider)
)
}
return contractMap.get(`TornadoProxy${network}`) as TornadoProxy
@ -178,7 +174,7 @@ export namespace Contracts {
key,
_getContract<TornadoInstance>(
'TornadoInstance',
await OnchainData.getInstanceAddress(network, token, denomination),
await Onchain.getInstanceAddress(network, token, denomination),
signerOrProvider
)
)

@ -1,5 +1,5 @@
// ts-essentials
import { DeepRequired, MarkOptional, MarkRequired } from 'ts-essentials'
import { DeepRequired, MarkOptional } from 'ts-essentials'
// Local types
import { RelayerProperties as RelayerDataProperties } from 'types/sdk/data'
@ -8,6 +8,7 @@ import { ZKDepositData, InputFor } from 'types/sdk/crypto'
import { TornadoInstance, TornadoProxy } from 'types/deth'
// External imports
import { EventEmitter } from 'stream'
import { BigNumber, EventFilter, providers } from 'ethers'
import { parseUnits } from 'ethers/lib/utils'
import { bigInt } from 'snarkjs'
@ -16,10 +17,10 @@ import { bigInt } from 'snarkjs'
import { parseIndexableString } from 'pouchdb-collate'
// Local imports
import { Docs, Cache, Types as DataTypes, Json, Constants, OnchainData } from 'lib/data'
import { Docs, Cache, Types as DataTypes, Json, Constants, Onchain } from 'lib/data'
import { Primitives } from 'lib/crypto'
import { Contracts, Chain } from 'lib/chain'
import { ErrorUtils, ObjectUtils } from 'lib/utils'
import { ErrorUtils, ObjectUtils, AsyncUtils } from 'lib/utils'
type Provider = providers.Provider
@ -36,12 +37,13 @@ type RelayerProperties = MarkOptional<
'serviceFeePercent' | 'prices'
>
export class Core {
export class Core extends EventEmitter {
chain: Chain
caches: Map<string, Cache.Base<Docs.Base>>
instances: Map<string, TornadoInstance>
constructor(provider: providers.Provider) {
super()
this.chain = new Chain(provider)
this.caches = new Map<string, Cache.Syncable<Docs.Base>>()
this.instances = new Map<string, TornadoInstance>()
@ -110,8 +112,6 @@ export class Core {
const hexNullifierHashes: string[] = []
const purchaseAmounts = options?.ethPurchaseAmounts ?? new Array(zkDepositsData.length)
console.log('\nChecking inputs.\n')
if (zkDepositsData.length !== recipientAddresses.length)
throw ErrorUtils.getError(
'Core.buildDepositProofs: the number of recipients must equal the length of zkDepositsData.'
@ -127,14 +127,10 @@ export class Core {
hexNullifierHashes.push(deposit.hexNullifierHash)
})
console.log('\nGetting lookup keys.\n')
// Determine cache name
const lookupKeys = await this.getInstanceLookupKeys(instance.address)
const lookupKeys = await Onchain.getInstanceLookupKeys(instance.address)
const name = 'Deposits' + (lookupKeys.network + lookupKeys.token + lookupKeys.denomination).toUpperCase()
console.log('\nLeaves and indices.\n')
// Find all leaves & indices by reading from cache
const [leaves, leafIndices] = await this._findLeavesAndIndices(name, hexCommitments)
const invalidCommitments: string[] = []
@ -143,8 +139,6 @@ export class Core {
const checkSpent = options?.checkNotesSpent !== false
const spentNotes: string[] = []
console.log('\nNote checking.\n')
// If yes, immediately check it with the supplied Tornado Instance
const checkSpentArray = checkSpent ? await instance.isSpentArray(hexNullifierHashes) : undefined
@ -161,8 +155,6 @@ export class Core {
const commitmentsAreInvalid = invalidCommitments.length !== 0
const notesAreSpent = spentNotes.length !== 0
console.log('\nErrors.\n')
if (commitmentsAreInvalid || notesAreSpent)
throw ErrorUtils.getError(
`Core.buildDepositProofs: ` +
@ -176,8 +168,6 @@ export class Core {
: '')
)
console.log('\nMerkle tree.\n')
// Otherwise, build the merkle tree from the leaves
const merkleTree = Primitives.buildMerkleTree({
height: options?.merkleTreeHeight ?? Constants.MERKLE_TREE_HEIGHT,
@ -193,8 +183,6 @@ export class Core {
'Core.buildDepositProofs: the merkle tree created is not valid, something went wrong with syncing.'
)
console.log('\nProof data invariant.\n')
// Rest of note invariant arguments
const inputsForProofs: InputFor.ZKProof[] = []
const gasPrice = options?.gasPrice ?? (await this.chain.getGasPrice())
@ -207,7 +195,7 @@ export class Core {
const decimals =
// @ts-expect-error
bigInt(10).pow(
options?.tokenDecimals ?? (await OnchainData.getTokenDecimals(lookupKeys.network, lookupKeys.token))
options?.tokenDecimals ?? (await Onchain.getTokenDecimals(lookupKeys.network, lookupKeys.token))
)
const toWithdraw = BigNumber.from(lookupKeys.denomination).mul(decimals)
@ -217,8 +205,6 @@ export class Core {
'Core.buildDepositProofs: a token price MUST be supplied if the token withdrawn is not native.'
)
console.log('\nConstruct.\n')
// Compute proofs
for (let i = 0, len = zkDepositsData.length; i < len; i++) {
inputsForProofs.push({
@ -248,8 +234,6 @@ export class Core {
})
}
console.log('\nCalc and return.\n')
return await Primitives.calcDepositProofs(inputsForProofs)
}
@ -285,13 +269,13 @@ export class Core {
if (indexes)
for (let i = 0, len = rows.length; i < len; i++) {
const id = parseIndexableString(rows[i].id)[0]
if (id === indexes[i]) docs.push(rows[i].doc)
if (0 < indexes.findIndex(id)) docs.push(rows[i].doc)
}
else docs = rows.map((row) => row.doc)
if (keys)
docs.forEach((doc) => {
const idNetworkMatches = doc && keys.network ? keys.network === doc?.network : true
const idNetworkMatches = doc && (keys.network ? keys.network === doc?.network : true)
const andTokenSymbolMatches = idNetworkMatches && (keys.token ? keys.token === doc?.token : true)
const lastlyDenominationMatches =
andTokenSymbolMatches && (keys.denomination ? keys.denomination === doc?.denomination : true)
@ -328,19 +312,19 @@ export class Core {
options.backup.invoices = options.backup.invoices ?? true
options.backup.notes = options.backup.notes ?? true
options.doNotPopulate = options.doNotPopulate ?? true
return this.buildDepositTxs(instances, options)
return this.buildDepositTransactions(instances, options)
}
async buildDepositTx(
async buildDepositTransaction(
instance: TornadoInstance,
options?: Options.Core.Deposit
): Promise<Transactions.Deposit> {
let opts: Options.Core.Deposit = options ?? {}
opts.depositsPerInstance = [1]
return (await this.buildDepositTxs([instance], opts))[0]
return (await this.buildDepositTransactions([instance], opts))[0]
}
async buildDepositTxs(
async buildDepositTransactions(
instances: Array<TornadoInstance>,
options?: Options.Core.Deposit
): Promise<Array<Transactions.Deposit>> {
@ -363,7 +347,7 @@ export class Core {
const proxy: TornadoProxy = await Contracts.getProxy(String(chainId), this.chain.provider)
for (let i = 0, nInstances = instances.length; i < nInstances; i++) {
const lookupKeys = await this.getInstanceLookupKeys(instances[i].address)
const lookupKeys = await Onchain.getInstanceLookupKeys(instances[i].address)
const pathstring = lookupKeys.network + lookupKeys.token + lookupKeys.denomination
for (let d = 0, nDeposits = depositsPerInstance[i]; d < nDeposits; d++) {
@ -441,11 +425,25 @@ export class Core {
})
}
loadCache<T extends Docs.Base, C extends Cache.Base<T>>(cacheName: string): C {
if (!this.caches.has(cacheName)) {
this.caches.set(cacheName, new Cache.Base<T>(cacheName))
loadWithdrawalCache(name: string, options?: Options.Core.Cache): Cache.Withdrawal {
if (!this.caches.has(name)) {
this.caches.set(name, new Cache.Withdrawal(name, options))
}
return this.caches.get(cacheName) as C
return this.caches.get(name) as Cache.Withdrawal
}
loadDepositCache(name: string, options?: Options.Core.Cache): Cache.Deposit {
if (!this.caches.has(name)) {
this.caches.set(name, new Cache.Deposit(name, options))
}
return this.caches.get(name) as Cache.Deposit
}
loadCache<T extends Docs.Base, C extends Cache.Base<T>>(name: string, options?: Options.Cache.Database): C {
if (!this.caches.has(name)) {
this.caches.set(name, new Cache.Base<T>(name, options))
}
return this.caches.get(name) as C
}
async syncMultiple(instances: Array<TornadoInstance>, syncOptions?: Options.Core.Sync): Promise<void> {
@ -456,7 +454,7 @@ export class Core {
async sync(instance: TornadoInstance, syncOptions?: Options.Core.Sync): Promise<void> {
// Get some data
const lookupKeys = await this.getInstanceLookupKeys(instance.address)
const lookupKeys = await Onchain.getInstanceLookupKeys(instance.address)
const populatedSyncOpts = await this._populateSyncOpts(lookupKeys, syncOptions)
@ -464,46 +462,41 @@ export class Core {
// Synchronize
for (let i = 0, bound = actions.length; i < bound; i++) {
let action = actions[i][0].charAt(0).toUpperCase() + actions[i][0].slice(1)
await this._sync(action, lookupKeys, instance, populatedSyncOpts)
const action = actions[i][0].charAt(0).toUpperCase() + actions[i][0].slice(1)
const pathstring = lookupKeys.network + lookupKeys.token + lookupKeys.denomination
const name = action + 's' + pathstring.toUpperCase()
if (action == 'Deposit')
await this._sync(
pathstring,
this.loadDepositCache(name, syncOptions?.cache),
instance.filters.Deposit(null, null, null),
instance,
populatedSyncOpts
)
else if (action == 'Withdrawal')
await this._sync(
pathstring,
this.loadWithdrawalCache(name, syncOptions?.cache),
instance.filters.Withdrawal(null, null, null, null),
instance,
populatedSyncOpts
)
}
}
private async _sync(
action: string,
lookupKeys: DataTypes.Keys.InstanceLookup,
pathstring: string,
cache: Cache.Syncable<Docs.Base>,
filter: EventFilter,
instance: TornadoInstance,
syncOptions: DeepRequired<Options.Core.Sync>
): Promise<void> {
const name = `${action + 's'}${lookupKeys.network}${lookupKeys.token.toUpperCase()}${
lookupKeys.denomination
}`,
pathstring = name.substring(action.length).toLowerCase()
let cache: Cache.Syncable<Docs.Base>,
toDoc: (_: any) => Docs.Base,
filter: EventFilter,
numEntries: number
if (action == 'Deposit') {
toDoc = (resp: any) => new Docs.Deposit(resp)
cache = this.caches.has(name)
? (this.caches.get(name)! as Cache.Deposit)
: new Cache.Deposit(name, syncOptions.cache)
filter = instance.filters.Deposit(null, null, null)
} else {
toDoc = (resp: any) => new Docs.Withdrawal(resp)
cache = this.caches.has(name)
? (this.caches.get(name)! as Cache.Withdrawal)
: new Cache.Withdrawal(name, syncOptions.cache)
filter = instance.filters.Withdrawal(null, null, null, null)
}
// Assign pooler
cache.sync.pooler = await cache.sync.initializePooler(cache.getCallbacks(instance))
cache.sync.initializePooler(cache.getCallbacks(instance), cache.getErrorHandlers())
// Decide whether we have a latest block
numEntries = (await cache.db.info()).doc_count
const numEntries = (await cache.db.info()).doc_count
// Check for synced blocks
if (0 < numEntries) {
@ -518,6 +511,15 @@ export class Core {
// Start synchronizing
let dbPromises = []
this.emit(
'debug',
syncOptions.blocks.startBlock,
syncOptions.blocks.targetBlock,
syncOptions.blocks.blockDelta
)
this.emit('sync', 'syncing')
for (
let currentBlock = syncOptions.blocks.startBlock,
blockDelta = syncOptions.blocks.blockDelta,
@ -526,37 +528,46 @@ export class Core {
currentBlock < targetBlock;
currentBlock += blockDelta
) {
if (cache.sync.pooler.pending < concurrencyLimit) {
if (cache.sync.pooler!.pending < concurrencyLimit) {
const sum = currentBlock + blockDelta
await AsyncUtils.timeout(syncOptions.msTimeout)
if (currentBlock + blockDelta < targetBlock) {
await cache.sync.pooler.pool(currentBlock, sum)
await cache.sync.pooler!.pool(currentBlock, sum)
} else {
await cache.sync.pooler.pool(currentBlock, sum - (sum % targetBlock))
await cache.sync.pooler!.pool(currentBlock, sum - (sum % targetBlock))
}
this.emit('debug', currentBlock++, sum)
} else {
let res: Array<any> = await cache.sync.pooler.race()
let res: Array<any> = await cache.sync.pooler!.race()
if (res.length != 0)
dbPromises.push(
cache.db.bulkDocs(res.map((el) => toDoc(el))).catch((err) => {
cache.db.bulkDocs(res.map((el) => cache.buildDoc(el))).catch((err) => {
throw ErrorUtils.ensureError(err)
})
)
currentBlock -= blockDelta
}
}
this.emit('sync', 'synced')
// Immediately start listening if we're doing this
if (syncOptions.cache.sync.listen)
instance = instance.on(filter, (...eventArgs) => {
cache.db.put(toDoc(eventArgs[eventArgs.length - 1]))
cache.db.put(cache.buildDoc(eventArgs[eventArgs.length - 1]))
})
// Then wait for all pooler requests to resolve
let results = await cache.sync.pooler.all()
let results = await cache.sync.pooler!.all()
// Then transform them, we know the shape in forward
results = results.reduce((res: any[], response: any[]) => {
if (response[0]) response.forEach((el: any) => res.push(toDoc(el)))
if (response[0]) response.forEach((el: any) => res.push(cache.buildDoc(el)))
return res
}, [])
@ -570,7 +581,7 @@ export class Core {
// Finally, store the objects
if (!this.instances.has(pathstring)) this.instances.set(pathstring, instance)
if (!this.caches.has(name)) this.caches.set(name, cache)
if (!this.caches.has(cache.name)) this.caches.set(cache.name, cache)
}
private async _populateSyncOpts(
@ -594,16 +605,16 @@ export class Core {
// blocks
syncOptions.blocks.startBlock =
syncOptions.blocks.startBlock ??
(await OnchainData.getInstanceDeployBlockNum(
lookupKeys.network,
lookupKeys.token,
lookupKeys.denomination
))
(await Onchain.getInstanceDeployBlockNum(lookupKeys.network, lookupKeys.token, lookupKeys.denomination))
syncOptions.blocks.targetBlock = syncOptions.blocks.targetBlock ?? (await this.chain.latestBlockNum())
syncOptions.blocks.deltaDivisor = syncOptions.blocks.deltaDivisor ?? 100
syncOptions.blocks.blockDelta = this._getBlockDelta(syncOptions)
syncOptions.msTimeout = syncOptions.msTimeout ?? 200 // 5 requests per second
// cache
// db
syncOptions.cache.db.persistent = syncOptions.cache.db.persistent ?? true
@ -618,8 +629,8 @@ export class Core {
private _getBlockDelta(syncOptions?: Options.Core.Sync): number {
return Math.floor(
syncOptions?.blocks?.blockDelta ??
(syncOptions!.blocks!.targetBlock! - syncOptions!.blocks!.startBlock!) / 20
(syncOptions!.blocks!.targetBlock! - syncOptions!.blocks!.startBlock!) /
syncOptions!.blocks!.deltaDivisor!
)
}
@ -670,25 +681,6 @@ export class Core {
// Concat matched and all leaf indices
return [leaves, indices]
}
async getInstanceLookupKeys(instanceAddress: string): Promise<DataTypes.Keys.InstanceLookup> {
// lookup some stuff first
const lookupObj: { [key: string]: string } = Json.getValue(await Json.load('onchain/quickLookup.json'), [
'instanceAddresses'
])
const pathstring: string = Object.entries(lookupObj).find((el) => el[1] === instanceAddress)![0]
const network = pathstring.match('[0-9]+')![0],
token = pathstring.substring(network.length).match('[a-z]+')![0],
denomination = pathstring.substring(network.length + token.length)
return {
network: network,
token: token,
denomination: denomination
}
}
}
export { Transactions, Options }

@ -26,12 +26,15 @@ PouchDB.plugin(PouchDBAdapterMemory)
export namespace Files {
export type PathGetter = (relative: string) => string
export const getModulesPath = (relative: string): string => __dirname + '/../../node_modules/' + relative
export const getResourcePath = (relative: string): string => __dirname + '/../resources/' + relative
export const getCachePath = (relative: string): string => __dirname + '/../../cache/' + relative
export const getModulesPath = (relative: string, prefix?: string): string =>
(prefix ?? __dirname + '/../../node_modules/') + relative
export const getResourcePath = (relative: string, prefix?: string): string =>
(prefix ?? __dirname + '/../resources/') + relative
export const getCachePath = (relative: string, prefix?: string): string =>
(prefix ?? __dirname + '/../../cache/') + relative
export const cacheDirExists = (): boolean => existsSync(getCachePath(''))
export const makeCacheDir = (): void => mkdirSync(getCachePath(''))
export const cacheDirExists = (prefix?: string): boolean => existsSync(getCachePath('', prefix))
export const makeCacheDir = (prefix?: string): void => mkdirSync(getCachePath('', prefix))
export const loadRaw = (relative: string): Promise<Buffer> => readFile(getResourcePath(relative))
@ -123,7 +126,7 @@ export namespace Json {
// TODO: Decide whether to also cache the data instead of just loading it for the function call
export namespace OnchainData {
export namespace Onchain {
export async function getClassicInstanceData(
network: string,
token: string,
@ -141,24 +144,43 @@ export namespace OnchainData {
}
}
export async function getInstanceAttrSet<T>(
key: string,
export async function getInstanceLookupKeys(instanceAddress: string): Promise<Types.Keys.InstanceLookup> {
// lookup some stuff first
const lookupObj: { [key: string]: string } = await Json.load('onchain/instanceAddresses.json')
const pathstring: string = Object.entries(lookupObj).find((el) => el[1] === instanceAddress)![0]
const network = pathstring.match('[0-9]+')![0],
token = pathstring.substring(network.length).match('[a-z]+')![0],
denomination = pathstring.substring(network.length + token.length)
return {
network: network,
token: token,
denomination: denomination
}
}
export async function getPathstringBasedContent<T>(
filepath: string,
paths: Array<{
network?: string
token?: string
denomination?: string
}>
): Promise<Array<T>> {
const obj = await Json.load('onchain/quickLookup.json')
const obj = await Json.load(filepath)
return await Promise.all(
paths.map((path) =>
Json.getValue(obj, [key, `${path.network ?? '\0'}${path.token ?? '\0'}${path.denomination ?? '\0'}`])
Json.getValue(obj, [`${path.network ?? '\0'}${path.token ?? '\0'}${path.denomination ?? '\0'}`])
)
)
}
export async function getNetworkSymbol(networkId: string): Promise<string> {
return (await getInstanceAttrSet<string>('networkSymbols', [{ network: networkId }]))[0]
return (
await getPathstringBasedContent<string>('onchain/networkSymbols.json', [{ network: networkId }])
)[0]
}
export function getInstanceAddresses(
@ -168,7 +190,7 @@ export namespace OnchainData {
denomination: string
}>
): Promise<Array<string>> {
return getInstanceAttrSet<string>('instanceAddresses', paths)
return getPathstringBasedContent<string>('onchain/instanceAddresses.json', paths)
}
export async function getInstanceAddress(
@ -186,7 +208,7 @@ export namespace OnchainData {
denomination: string
}>
): Promise<Array<number>> {
return getInstanceAttrSet<number>('deployedBlockNumber', paths)
return getPathstringBasedContent<number>('onchain/deployedBlockNumbers.json', paths)
}
export async function getInstanceDeployBlockNum(
@ -220,12 +242,22 @@ export namespace OnchainData {
}
}
export async function getTokenAddress(network: string, token: string): Promise<string> {
return (
await getPathstringBasedContent<string>('onchain/tokenAddresses.json', [
{ network: network, token: token }
])
)[0]
}
export async function getTokenDecimals(network: string, token: string): Promise<number> {
return (await getTokenData(network, token)).decimals
return (
await getPathstringBasedContent<number>('onchain/decimals.json', [{ network: network, token: token }])
)[0]
}
}
export namespace OffchainData {
export namespace Offchain {
export async function getUncensoredRpcURL(network: string, name: string = ''): Promise<string> {
const rpcs = Json.toMap<string>(
Json.getValue(await Json.load('offchain/infrastructure.json'), ['jrpc-uncensored', network])
@ -366,9 +398,12 @@ export namespace Docs {
export namespace Cache {
export class Base<T extends Docs.Base> {
name: string
db: PouchDB.Database<T>
constructor(name: string, options?: Options.Cache.Database) {
this.name = name
if (options?.persistent === false && options?.adapter !== 'memory' && options?.adapter !== null)
throw ErrorUtils.getError('Cache.new: if not persistent, cache must use memory adapter.')
@ -404,8 +439,12 @@ export namespace Cache {
this.sync = new AsyncUtils.Sync(options?.sync)
}
abstract buildDoc(response: any): Docs.Base
abstract getCallbacks(...args: Array<any>): Array<AsyncUtils.Callback>
abstract getErrorHandlers(...args: Array<any>): Array<AsyncUtils.ErrorHandler>
async close(): Promise<void> {
if (this.sync.pooler!.pending)
throw ErrorUtils.getError("Syncable.close: can't clear while pooler still has pending promises.")
@ -419,7 +458,40 @@ export namespace Cache {
}
}
function tornadoSyncErrorHandler(
err: Error,
numResolvedPromises: number,
callbackIndex: number,
orderIndex: number,
...args: any[]
): void {
err = ErrorUtils.ensureError<Error>(err)
if (err.message.match('context deadline exceeded'))
console.error(
ErrorUtils.getError(
`Context deadline exceeded, stop if more promises do not resolve. Resolved: ${numResolvedPromises}`
)
)
else if (err.message.match('Invalid JSON RPC'))
console.error(
ErrorUtils.getError(`Endpoint returned invalid value (we might be rate limited), retrying.`)
)
else {
err.message += `\nCallback args supplied: [${args.join(', ')}]\n`
throw err
}
}
export class Deposit extends Syncable<Docs.Deposit> {
buildDoc(response: any): Docs.Deposit {
return new Docs.Deposit(response)
}
getErrorHandlers(): Array<AsyncUtils.ErrorHandler> {
return [tornadoSyncErrorHandler]
}
getCallbacks(instance: TornadoInstance): Array<AsyncUtils.Callback> {
return [
(fromBlock: number, toBlock: number) => {
@ -430,6 +502,14 @@ export namespace Cache {
}
export class Withdrawal extends Syncable<Docs.Withdrawal> {
buildDoc(response: any): Docs.Withdrawal {
return new Docs.Withdrawal(response)
}
getErrorHandlers(): Array<AsyncUtils.ErrorHandler> {
return [tornadoSyncErrorHandler]
}
getCallbacks(instance: TornadoInstance): Array<AsyncUtils.Callback> {
return [
(fromBlock: number, toBlock: number) => {

@ -2,7 +2,8 @@
import * as Crypto from 'types/sdk/crypto'
import { Options } from 'types/sdk/core'
// Needed
// External imports
import assert from 'assert'
import { BigNumber } from 'ethers'
import { bigInt } from 'snarkjs'
import { randomBytes } from 'crypto'
@ -22,7 +23,7 @@ export namespace ErrorUtils {
export function getError(message: string): Error {
let error = new Error(message)
error.name = 'Error (tornado-sdk)'
error.name = '\nError (tornado-sdk)'
return error
}
}
@ -34,25 +35,34 @@ export namespace AsyncUtils {
export type Callback = (...values: any[]) => Promise<any>
export type ErrorHandler = (
err: Error,
numResolvedPromises: number,
callbackIndex: number,
orderIndex: number,
...args: any[]
) => void
export class PromisePooler {
concurrencyLimit: number
private _totalAdded: number
_results: Array<any>
_callbacks: Array<Callback>
_errorHandlers: Array<ErrorHandler>
private _promises: Array<PoolPromise<any>>
constructor(callbacks: Array<Callback>, concurrencyLimit: number) {
constructor(callbacks: Array<Callback>, errorHandlers: Array<ErrorHandler>, concurrencyLimit: number) {
if (callbacks.length == 0) throw ErrorUtils.getError('PromisePooler: callbacks are empty.')
if (concurrencyLimit <= 0)
throw ErrorUtils.getError("PromisePooler: concurrencyLimit can't be 0 or less.")
this.concurrencyLimit = concurrencyLimit
this._totalAdded = 0
this._results = []
this._promises = []
this._callbacks = callbacks
this._errorHandlers = errorHandlers
}
get pending(): number {
@ -98,10 +108,21 @@ export namespace AsyncUtils {
}
}
// TODO: Immediately set new callbacks and error handlers
async reset(): Promise<Array<any>> {
let results = await this.all()
this._callbacks = []
assert(
this._promises.length === 0,
ErrorUtils.getError('PromisePooler.reset: Resetting should have allowed all promises to resolve.')
)
this._results = []
this._totalAdded = 0
this._callbacks = []
this._errorHandlers = []
return results
}
@ -113,29 +134,42 @@ export namespace AsyncUtils {
return this._pool(callbackIndex + 1, orderIndex, ...results)
} else {
let result = results.length == 1 ? results[0] : results
this._promises.splice(
this._promises.findIndex((_promise) => _promise.orderIndex == orderIndex),
1
)
this._promises.splice(this._getPromiseIndex(orderIndex), 1)
this._results.push(result)
return result
}
},
(err) => {
throw ErrorUtils.ensureError(err)
async (err: Error) => {
let resolved = this._totalAdded - this.concurrencyLimit
resolved = resolved < 0 ? 0 : resolved
// Throw inside to abort
this._errorHandlers[callbackIndex](
ErrorUtils.ensureError<Error>(err),
resolved,
callbackIndex,
orderIndex,
...args
)
return this._pool(callbackIndex, orderIndex, ...args)
}
)
promise.orderIndex = orderIndex
if (callbackIndex == 0) {
const promiseIndex = this._getPromiseIndex(orderIndex)
if (promiseIndex < 0) {
this._promises.push(promise)
} else {
this._promises[this._promises.findIndex((_promise) => _promise.orderIndex == orderIndex)] = promise
this._promises[promiseIndex] = promise
}
return promise
}
private _getPromiseIndex(orderIndex: number): number {
return this._promises.findIndex((_promise) => _promise.orderIndex == orderIndex)
}
private async _waitIfFull(): Promise<void> {
if (this.concurrencyLimit <= this._promises.length) {
await Promise.race(this._promises)
@ -153,15 +187,14 @@ export namespace AsyncUtils {
this.listen = options?.listen ?? false
}
async initializePooler(callbacks: Array<Callback>): Promise<PromisePooler> {
return new PromisePooler(callbacks, this.concurrencyLimit)
initializePooler(callbacks: Array<Callback>, errorHandlers: Array<ErrorHandler>): void {
if (this.pooler) this.pooler.reset()
this.pooler = new PromisePooler(callbacks, errorHandlers, this.concurrencyLimit)
}
}
async newCallbacks(callbacks: Array<Callback>): Promise<Array<any>> {
let results = this.pooler!.reset()
this.pooler!._callbacks = callbacks
return results
}
export function timeout(msTimeout: number): Promise<any> {
return new Promise((resolve) => setTimeout(resolve, msTimeout))
}
}

@ -49,7 +49,9 @@ export class TorProvider extends Web3Provider {
agent: { https: new SocksProxyAgent('socks5h://127.0.0.1:' + torPort) },
// The XHR2 XMLHttpRequest assigns a Tor Browser header by itself.
// But if in Browser we assign just in case.
headers: typeof window !== 'undefined' ? headers : undefined
headers: typeof window !== 'undefined' ? headers : undefined,
// 1 minute timeout, although not sure if this is behaving properly
timeout: 60000
}),
network
)
@ -135,10 +137,12 @@ export class Relayer {
this._serviceFee = properties['tornadoServiceFee']
this._miningFee = properties['miningFee']
this._status = properties['health']['status']
this._prices = Object.entries(properties['ethPrices']).reduce(
(map, entry) => map.set(entry[0], BigNumber.from(entry[1])),
new Map<string, BigNumber>()
)
this._fetched = true
return {

@ -0,0 +1 @@
{"1eth":18,"1dai":18,"1cdai":8,"1usdc":6,"1usdt":6,"1wbtc":8,"5eth":18,"5dai":18,"5cdai":8,"5usdc":6,"5usdt":6,"5wbtc":8,"10eth":18,"56bnb":18,"100xdai":18,"137matic":18,"42161eth":18,"43114avax":18}

@ -0,0 +1,66 @@
{
"1eth0.1": 9116966,
"1eth1": 9117609,
"1eth10": 9117720,
"1eth100": 9161895,
"1dai100": 9117612,
"1dai1000": 9161917,
"1dai10000": 12066007,
"1dai100000": 12066048,
"1cdai5000": 9161938,
"1cdai50000": 12069037,
"1cdai500000": 12067606,
"1cdai5000000": 12066053,
"1usdc100": 9161958,
"1usdc1000": 9161965,
"1usdc10000": null,
"1usdc100000": null,
"1usdt100": 9162005,
"1usdt1000": 9162012,
"1usdt10000": null,
"1usdt100000": null,
"1wbtc0.1": 12067529,
"1wbtc1": 12066652,
"1wbtc10": 12067591,
"1wbtc100": null,
"5eth0.1": 3782581,
"5eth1": 3782590,
"5eth10": 3782593,
"5eth100": 3782596,
"5dai100": 4339088,
"5dai1000": 4367659,
"5dai10000": 4441492,
"5dai100000": 4441488,
"5cdai5000": 4441443,
"5cdai50000": 4441489,
"5cdai500000": 4441493,
"5cdai5000000": 4441489,
"5usdc100": 4441426,
"5usdc1000": 4441492,
"5usdc10000": null,
"5usdc100000": null,
"5usdt100": 4441490,
"5usdt1000": 4441492,
"5usdt10000": null,
"5usdt100000": null,
"5wbtc0.1": 4441488,
"5wbtc1": 4441490,
"5wbtc10": 4441490,
"5wbtc100": null,
"56bnb0.1": 8159279,
"56bnb1": 8159286,
"56bnb10": 8159290,
"56bnb100": 8159296,
"100xdai100": 17754566,
"100xdai1000": 17754568,
"100xdai10000": 17754572,
"100xdai100000": 17754574,
"137matic100": 16258013,
"137matic1000": 16258032,
"137matic10000": 16258046,
"137matic100000": 16258053,
"42161eth0.1": 3300000,
"42161eth1": 3300000,
"42161eth10": 3300000,
"42161eth100": 3300000
}

@ -0,0 +1,66 @@
{
"1eth0.1": "0x12D66f87A04A9E220743712cE6d9bB1B5616B8Fc",
"1eth1": "0x47CE0C6eD5B0Ce3d3A51fdb1C52DC66a7c3c2936",
"1eth10": "0x910Cbd523D972eb0a6f4cAe4618aD62622b39DbF",
"1eth100": "0xA160cdAB225685dA1d56aa342Ad8841c3b53f291",
"1dai100": "0xD4B88Df4D29F5CedD6857912842cff3b20C8Cfa3",
"1dai1000": "0xFD8610d20aA15b7B2E3Be39B396a1bC3516c7144",
"1dai10000": "0x07687e702b410Fa43f4cB4Af7FA097918ffD2730",
"1dai100000": "0x23773E65ed146A459791799d01336DB287f25334",
"1cdai5000": "0x22aaA7720ddd5388A3c0A3333430953C68f1849b",
"1cdai50000": "0x03893a7c7463AE47D46bc7f091665f1893656003",
"1cdai500000": "0x2717c5e28cf931547B621a5dddb772Ab6A35B701",
"1cdai5000000": "0xD21be7248e0197Ee08E0c20D4a96DEBdaC3D20Af",
"1usdc100": "0xd96f2B1c14Db8458374d9Aca76E26c3D18364307",
"1usdc1000": "0x4736dCf1b7A3d580672CcE6E7c65cd5cc9cFBa9D",
"1usdc10000": null,
"1usdc100000": null,
"1usdt100": "0x169AD27A470D064DEDE56a2D3ff727986b15D52B",
"1usdt1000": "0x0836222F2B2B24A3F36f98668Ed8F0B38D1a872f",
"1usdt10000": null,
"1usdt100000": null,
"1wbtc0.1": "0x178169B423a011fff22B9e3F3abeA13414dDD0F1",
"1wbtc1": "0x610B717796ad172B316836AC95a2ffad065CeaB4",
"1wbtc10": "0xbB93e510BbCD0B7beb5A853875f9eC60275CF498",
"1wbtc100": null,
"5eth0.1": "0x6Bf694a291DF3FeC1f7e69701E3ab6c592435Ae7",
"5eth1": "0x3aac1cC67c2ec5Db4eA850957b967Ba153aD6279",
"5eth10": "0x723B78e67497E85279CB204544566F4dC5d2acA0",
"5eth100": "0x0E3A09dDA6B20aFbB34aC7cD4A6881493f3E7bf7",
"5dai100": "0x76D85B4C0Fc497EeCc38902397aC608000A06607",
"5dai1000": "0xCC84179FFD19A1627E79F8648d09e095252Bc418",
"5dai10000": "0xD5d6f8D9e784d0e26222ad3834500801a68D027D",
"5dai100000": "0x407CcEeaA7c95d2FE2250Bf9F2c105aA7AAFB512",
"5cdai5000": "0x833481186f16Cece3f1Eeea1a694c42034c3a0dB",
"5cdai50000": "0xd8D7DE3349ccaA0Fde6298fe6D7b7d0d34586193",
"5cdai500000": "0x8281Aa6795aDE17C8973e1aedcA380258Bc124F9",
"5cdai5000000": "0x57b2B8c82F065de8Ef5573f9730fC1449B403C9f",
"5usdc100": "0x05E0b5B40B7b66098C2161A5EE11C5740A3A7C45",
"5usdc1000": "0x23173fE8b96A4Ad8d2E17fB83EA5dcccdCa1Ae52",
"5usdc10000": null,
"5usdc100000": null,
"5usdt100": "0x538Ab61E8A9fc1b2f93b3dd9011d662d89bE6FE6",
"5usdt1000": "0x94Be88213a387E992Dd87DE56950a9aef34b9448",
"5usdt10000": null,
"5usdt100000": null,
"5wbtc0.1": "0x242654336ca2205714071898f67E254EB49ACdCe",
"5wbtc1": "0x776198CCF446DFa168347089d7338879273172cF",
"5wbtc10": "0xeDC5d01286f99A066559F60a585406f3878a033e",
"5wbtc100": null,
"56bnb0.1": "0x84443CFd09A48AF6eF360C6976C5392aC5023a1F",
"56bnb1": "0xd47438C816c9E7f2E2888E060936a499Af9582b3",
"56bnb10": "0x330bdFADE01eE9bF63C209Ee33102DD334618e0a",
"56bnb100": "0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD",
"100xdai100": "0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD",
"100xdai1000": "0xdf231d99Ff8b6c6CBF4E9B9a945CBAcEF9339178",
"100xdai10000": "0xaf4c0B70B2Ea9FB7487C7CbB37aDa259579fe040",
"100xdai100000": "0xa5C2254e4253490C54cef0a4347fddb8f75A4998",
"137matic100": "0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD",
"137matic1000": "0xdf231d99Ff8b6c6CBF4E9B9a945CBAcEF9339178",
"137matic10000": "0xaf4c0B70B2Ea9FB7487C7CbB37aDa259579fe040",
"137matic100000": "0xa5C2254e4253490C54cef0a4347fddb8f75A4998",
"42161eth0.1": "0x84443CFd09A48AF6eF360C6976C5392aC5023a1F",
"42161eth1": "0xd47438C816c9E7f2E2888E060936a499Af9582b3",
"42161eth10": "0x330bdFADE01eE9bF63C209Ee33102DD334618e0a",
"42161eth100": "0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD"
}

@ -0,0 +1,8 @@
{
"1": "eth",
"5": "eth",
"56": "bnb",
"100": "xdai",
"137": "matic",
"42161": "eth"
}

@ -1,142 +0,0 @@
{
"instanceAddresses": {
"1eth0.1": "0x12D66f87A04A9E220743712cE6d9bB1B5616B8Fc",
"1eth1": "0x47CE0C6eD5B0Ce3d3A51fdb1C52DC66a7c3c2936",
"1eth10": "0x910Cbd523D972eb0a6f4cAe4618aD62622b39DbF",
"1eth100": "0xA160cdAB225685dA1d56aa342Ad8841c3b53f291",
"1dai100": "0xD4B88Df4D29F5CedD6857912842cff3b20C8Cfa3",
"1dai1000": "0xFD8610d20aA15b7B2E3Be39B396a1bC3516c7144",
"1dai10000": "0x07687e702b410Fa43f4cB4Af7FA097918ffD2730",
"1dai100000": "0x23773E65ed146A459791799d01336DB287f25334",
"1cdai5000": "0x22aaA7720ddd5388A3c0A3333430953C68f1849b",
"1cdai50000": "0x03893a7c7463AE47D46bc7f091665f1893656003",
"1cdai500000": "0x2717c5e28cf931547B621a5dddb772Ab6A35B701",
"1cdai5000000": "0xD21be7248e0197Ee08E0c20D4a96DEBdaC3D20Af",
"1usdc100": "0xd96f2B1c14Db8458374d9Aca76E26c3D18364307",
"1usdc1000": "0x4736dCf1b7A3d580672CcE6E7c65cd5cc9cFBa9D",
"1usdc10000": null,
"1usdc100000": null,
"1usdt100": "0x169AD27A470D064DEDE56a2D3ff727986b15D52B",
"1usdt1000": "0x0836222F2B2B24A3F36f98668Ed8F0B38D1a872f",
"1usdt10000": null,
"1usdt100000": null,
"1wbtc0.1": "0x178169B423a011fff22B9e3F3abeA13414dDD0F1",
"1wbtc1": "0x610B717796ad172B316836AC95a2ffad065CeaB4",
"1wbtc10": "0xbB93e510BbCD0B7beb5A853875f9eC60275CF498",
"1wbtc100": null,
"5eth0.1": "0x6Bf694a291DF3FeC1f7e69701E3ab6c592435Ae7",
"5eth1": "0x3aac1cC67c2ec5Db4eA850957b967Ba153aD6279",
"5eth10": "0x723B78e67497E85279CB204544566F4dC5d2acA0",
"5eth100": "0x0E3A09dDA6B20aFbB34aC7cD4A6881493f3E7bf7",
"5dai100": "0x76D85B4C0Fc497EeCc38902397aC608000A06607",
"5dai1000": "0xCC84179FFD19A1627E79F8648d09e095252Bc418",
"5dai10000": "0xD5d6f8D9e784d0e26222ad3834500801a68D027D",
"5dai100000": "0x407CcEeaA7c95d2FE2250Bf9F2c105aA7AAFB512",
"5cdai5000": "0x833481186f16Cece3f1Eeea1a694c42034c3a0dB",
"5cdai50000": "0xd8D7DE3349ccaA0Fde6298fe6D7b7d0d34586193",
"5cdai500000": "0x8281Aa6795aDE17C8973e1aedcA380258Bc124F9",
"5cdai5000000": "0x57b2B8c82F065de8Ef5573f9730fC1449B403C9f",
"5usdc100": "0x05E0b5B40B7b66098C2161A5EE11C5740A3A7C45",
"5usdc1000": "0x23173fE8b96A4Ad8d2E17fB83EA5dcccdCa1Ae52",
"5usdc10000": null,
"5usdc100000": null,
"5usdt100": "0x538Ab61E8A9fc1b2f93b3dd9011d662d89bE6FE6",
"5usdt1000": "0x94Be88213a387E992Dd87DE56950a9aef34b9448",
"5usdt10000": null,
"5usdt100000": null,
"5wbtc0.1": "0x242654336ca2205714071898f67E254EB49ACdCe",
"5wbtc1": "0x776198CCF446DFa168347089d7338879273172cF",
"5wbtc10": "0xeDC5d01286f99A066559F60a585406f3878a033e",
"5wbtc100": null,
"56bnb0.1": "0x84443CFd09A48AF6eF360C6976C5392aC5023a1F",
"56bnb1": "0xd47438C816c9E7f2E2888E060936a499Af9582b3",
"56bnb10": "0x330bdFADE01eE9bF63C209Ee33102DD334618e0a",
"56bnb100": "0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD",
"100xdai100": "0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD",
"100xdai1000": "0xdf231d99Ff8b6c6CBF4E9B9a945CBAcEF9339178",
"100xdai10000": "0xaf4c0B70B2Ea9FB7487C7CbB37aDa259579fe040",
"100xdai100000": "0xa5C2254e4253490C54cef0a4347fddb8f75A4998",
"137matic100": "0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD",
"137matic1000": "0xdf231d99Ff8b6c6CBF4E9B9a945CBAcEF9339178",
"137matic10000": "0xaf4c0B70B2Ea9FB7487C7CbB37aDa259579fe040",
"137matic100000": "0xa5C2254e4253490C54cef0a4347fddb8f75A4998",
"42161eth0.1": "0x84443CFd09A48AF6eF360C6976C5392aC5023a1F",
"42161eth1": "0xd47438C816c9E7f2E2888E060936a499Af9582b3",
"42161eth10": "0x330bdFADE01eE9bF63C209Ee33102DD334618e0a",
"42161eth100": "0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD"
},
"deployedBlockNumber": {
"1eth0.1": 9116966,
"1eth1": 9117609,
"1eth10": 9117720,
"1eth100": 9161895,
"1dai100": 9117612,
"1dai1000": 9161917,
"1dai10000": 12066007,
"1dai100000": 12066048,
"1cdai5000": 9161938,
"1cdai50000": 12069037,
"1cdai500000": 12067606,
"1cdai5000000": 12066053,
"1usdc100": 9161958,
"1usdc1000": 9161965,
"1usdc10000": null,
"1usdc100000": null,
"1usdt100": 9162005,
"1usdt1000": 9162012,
"1usdt10000": null,
"1usdt100000": null,
"1wbtc0.1": 12067529,
"1wbtc1": 12066652,
"1wbtc10": 12067591,
"1wbtc100": null,
"5eth0.1": 3782581,
"5eth1": 3782590,
"5eth10": 3782593,
"5eth100": 3782596,
"5dai100": 4339088,
"5dai1000": 4367659,
"5dai10000": 4441492,
"5dai100000": 4441488,
"5cdai5000": 4441443,
"5cdai50000": 4441489,
"5cdai500000": 4441493,
"5cdai5000000": 4441489,
"5usdc100": 4441426,
"5usdc1000": 4441492,
"5usdc10000": null,
"5usdc100000": null,
"5usdt100": 4441490,
"5usdt1000": 4441492,
"5usdt10000": null,
"5usdt100000": null,
"5wbtc0.1": 4441488,
"5wbtc1": 4441490,
"5wbtc10": 4441490,
"5wbtc100": null,
"56bnb0.1": 8159279,
"56bnb1": 8159286,
"56bnb10": 8159290,
"56bnb100": 8159296,
"100xdai100": 17754566,
"100xdai1000": 17754568,
"100xdai10000": 17754572,
"100xdai100000": 17754574,
"137matic100": 16258013,
"137matic1000": 16258032,
"137matic10000": 16258046,
"137matic100000": 16258053,
"42161eth0.1": 3300000,
"42161eth1": 3300000,
"42161eth10": 3300000,
"42161eth100": 3300000
},
"networkSymbols": {
"1": "eth",
"5": "eth",
"56": "bnb",
"100": "xdai",
"137": "matic",
"42161": "eth"
}
}

@ -0,0 +1 @@
{"1dai":"0x6B175474E89094C44Da98b954EedeAC495271d0F","1cdai":"0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643","1usdc":"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48","1usdt":"0xdAC17F958D2ee523a2206206994597C13D831ec7","1wbtc":"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599","5dai":"0xdc31Ee1784292379Fbb2964b3B9C4124D8F89C60","5cdai":"0x822397d9a55d0fefd20F5c4bCaB33C5F65bd28Eb","5usdc":"0xD87Ba7A50B2E7E660f678A895E4B72E7CB4CCd9C","5usdt":"0xb7FC2023D96AEa94Ba0254AA5Aeb93141e4aad66","5wbtc":"0xC04B0d3107736C32e19F1c62b2aF67BE61d63a05"}

@ -9,7 +9,7 @@ import { ERC20, TornadoInstance } from 'types/deth'
import { Json } from 'types/sdk/data'
import { Core } from 'lib/core'
import { Chain, Contracts } from 'lib/chain'
import { Docs, Files, OnchainData, Cache } from 'lib/data'
import { Docs, Files, Onchain, Cache } from 'lib/data'
import { ErrorUtils } from 'lib/utils'
import { TorProvider } from 'lib/web'
@ -24,7 +24,7 @@ chai.use(solidity)
const expect = chai.expect
describe.only('main', () => {
describe('main', () => {
const torify = process.env.TORIFY === 'true'
if (!process.env.ETH_MAINNET_TEST_RPC) throw ErrorUtils.getError('need a mainnet rpc endpoint.')
@ -34,11 +34,11 @@ describe.only('main', () => {
'Also, we are using ganache because we just need a forked blockchain and not an entire environment. 🐧'
)
let daiData: Json.TokenData
let daiAddress: string
const daiWhale = '0x5777d92f208679db4b9778590fa3cab3ac9e2168' // Uniswap V3 Something/Dai Pool
const mainnetProvider = torify
? new TorProvider(process.env.ETH_MAINNET_TEST_RPC, { port: +process.env.TOR_PORT! })
const mainnetProvider: providers.Provider = torify
? new TorProvider(process.env.ETH_MAINNET_TEST_RPC!, { port: +process.env.TOR_PORT! })
: new providers.JsonRpcProvider(process.env.ETH_MAINNET_TEST_RPC)
const _ganacheProvider = ganache.provider({
@ -54,6 +54,7 @@ describe.only('main', () => {
// @ts-expect-error
const ganacheProvider = new providers.Web3Provider(_ganacheProvider)
const chain = new Chain(ganacheProvider)
let snapshotId: any
@ -64,7 +65,7 @@ describe.only('main', () => {
})
describe('namespace Tornado', () => {
describe.skip('namespace Contracts', () => {
describe('namespace Contracts', () => {
it('getClassicInstance: should be able to get a tornado instance', async () => {
let instance = await Contracts.getInstance(String(1), 'eth', String(1), mainnetProvider)
expect(instance.address).to.equal('0x47CE0C6eD5B0Ce3d3A51fdb1C52DC66a7c3c2936')
@ -73,21 +74,30 @@ describe.only('main', () => {
})
describe('class Classic', () => {
it.skip('sync: Should be able to fetch deposit events', async () => {
it.only('sync: Should be able to fetch deposit events', async function () {
const core = new Core(mainnetProvider)
const instance = await Contracts.getInstance(String(1), 'eth', String(0.1), mainnetProvider)
//const targetBlock = 16928712
//const startBlock = targetBlock - 7200
// For safety
expect(torify).to.be.true
core.on('debug', function (...args) {
if (args.length === 3) {
console.debug(`\nSync will be started with SB: ${args[0]}, TB: ${args[1]}, BD: ${args[2]}\n`)
} else if (args.length == 2) {
console.debug(`Syncing from block ${args[0]} to ${args[1]}`)
}
})
// This is going to try syncing the entire range
await core.sync(instance, {
//deposit: true,
//withdrawal: false,
blocks: {
//startBlock: startBlock,
//targetBlock: targetBlock
deltaDivisor: 50
},
cache: {
sync: {
concurrencyLimit: 10
concurrencyLimit: 20
}
}
})
@ -124,8 +134,8 @@ describe.only('main', () => {
await ganacheProvider.send('evm_setAccountBalance', [daiWhale, parseUnits('10').toHexString()])
needsMoneyAddress = await needsMoney.getAddress()
daiData = await OnchainData.getTokenData('1', 'dai')
dai = chain.getTokenContract(daiData.address).connect(whale)
daiAddress = await Onchain.getTokenAddress('1', 'dai')
dai = chain.getTokenContract(daiAddress).connect(whale)
smallestEth = await core.getInstance('eth', 0.1)
})
after(async function () {
@ -137,11 +147,11 @@ describe.only('main', () => {
dai = dai.connect(whale)
})
it.only('buildDepositTx: build a single eth deposit tx and succeed', async () => {
it('buildDepositTransaction: build a single eth deposit tx and succeed', async () => {
const signer = ganacheProvider.getSigner()
const initBal = await signer.getBalance()
const tx = await core.buildDepositTx(smallestEth)
const tx = await core.buildDepositTransaction(smallestEth)
const response = await signer.sendTransaction(tx.request)
const receipt = await response.wait()
@ -165,7 +175,7 @@ describe.only('main', () => {
expect(endBal).to.be.lte(parseUnits('999.9'))
}).timeout(0)
it.only('buildDepositProofs: it should be able to build', async () => {
it('buildDepositProofs: it should be able to build', async () => {
try {
const instance = await core.getInstance('eth', 0.1)
const signer = ganacheProvider.getSigner()
@ -175,8 +185,9 @@ describe.only('main', () => {
noteObj['args'] = {
commitment: note.hexCommitment,
leafIndex: (await cache!.db.allDocs({ descending: true, limit: 1, include_docs: true }))
?.rows[0].doc?.leafIndex,
leafIndex:
(await cache!.db.allDocs({ descending: true, limit: 1, include_docs: true }))?.rows[0].doc
?.leafIndex! + 1,
timestamp: noteObj['args']['timestamp']
}
@ -184,15 +195,16 @@ describe.only('main', () => {
await cache!.db.put(new Docs.Deposit(noteObj))
console.log(`\nBuilding proof from note:\n\n${note}\n\n`)
const proof = await core.buildDepositProof(
instance,
{
address: await withdrawer.getAddress()
},
await signer.getAddress(),
note
note,
{
checkNotesSpent: false
}
)
console.log(proof)
@ -202,7 +214,7 @@ describe.only('main', () => {
}
}).timeout(0)
it.skip('buildDepositTx: build a single token deposit tx and succeed', async () => {
it('buildDepositTransaction: build a single token deposit tx and succeed', async () => {
const dai100K = await core.getInstance('dai', 100000)
const proxy = await core.getProxy()
const depositAmount = parseUnits('100000')
@ -210,7 +222,7 @@ describe.only('main', () => {
await dai.transfer(needsMoneyAddress, depositAmount)
dai = dai.connect(needsMoney)
const tx = await core.buildDepositTx(dai100K)
const tx = await core.buildDepositTransaction(dai100K)
await dai.approve(proxy.address, depositAmount)
@ -219,13 +231,13 @@ describe.only('main', () => {
expect(await dai.balanceOf(needsMoneyAddress)).to.equal(0)
}).timeout(0)
it.skip('buildDepositTxs: multiple eth deposits', async () => {
it('buildDepositTransactions: multiple eth deposits', async () => {
const instances = await core.getInstances(
[0.1, 1, 10, 100].map((el) => {
return { token: 'eth', denomination: el }
})
)
const txs = await core.buildDepositTxs(instances, {
const txs = await core.buildDepositTransactions(instances, {
depositsPerInstance: [1, 2, 3, 4]
})
@ -236,7 +248,7 @@ describe.only('main', () => {
expect(await dai.balanceOf(needsMoneyAddress)).to.equal(0)
}).timeout(0)
it.skip('buildDepositTxs: multiple token deposits', async () => {
it('buildDepositTransactions: multiple token deposits', async () => {
const instances = await core.getInstances(
[100, 1000, 10000, 100000].map((el) => {
return { token: 'dai', denomination: el }
@ -249,7 +261,7 @@ describe.only('main', () => {
await dai.transfer(needsMoneyAddress, parseUnits('432100'))
dai = dai.connect(needsMoney)
const txs = await core.buildDepositTxs(instances, {
const txs = await core.buildDepositTransactions(instances, {
depositsPerInstance: [1, 2, 3, 4]
})
@ -262,7 +274,7 @@ describe.only('main', () => {
expect(await dai.balanceOf(needsMoneyAddress)).to.equal(0)
}).timeout(0)
it.skip('createInvoice: should be able to create an invoice', async () => {
it('createInvoice: should be able to create an invoice', async () => {
const instance = await core.getInstance('dai', '1000')
const invoice = await core.createInvoice(instance)
console.log(invoice)

@ -21,18 +21,22 @@ export namespace Options {
}
export namespace Core {
export interface Cache {
sync?: Cache.Sync
db?: Cache.Database
}
export interface Sync {
deposit?: boolean
withdrawal?: boolean
msTimeout?: number
blocks?: {
startBlock?: number
targetBlock?: number
blockDelta?: number
deltaDivisor?: number
}
cache?: {
sync?: Cache.Sync
db?: Cache.Database
}
cache?: Cache
}
export interface Deposit {