sdk-monorepo/@tornado/sdk-registry/src/index.ts

179 lines
5.3 KiB
TypeScript

// ts-essentials
import { DeepRequired, Merge } from 'ts-essentials'
// Contract types
import { RelayerRegistry } from './deth/RelayerRegistry.js'
// Local imports
import { AsyncUtils, ErrorUtils } from '@tornado/sdk-utils'
import { Docs, Cache, Onchain, Options as DataOptions } from '@tornado/sdk-data'
import { Chain, Synchronizer, Options as ChainOptions, syncErrorHandler } from '@tornado/sdk-chain'
// @ts-ignore
import { toIndexableString } from 'pouchdb-collate'
import { match } from 'assert'
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECLARATIONS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
export namespace Options {
export type Cache = DataOptions.Cache
export type Sync = ChainOptions.Sync
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IMPLEMENTATIONS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
export class Registrations extends Docs.Base {}
export class Stakes extends Docs.Base {}
export class Burns extends Docs.Base {}
export class RegistrationsCache extends Cache.Syncable<Registrations> {
// TODO: IMPLEMENT
buildDoc(response: any): Docs.Withdrawal {
return new Docs.Withdrawal(response)
}
getErrorHandlers(): Array<AsyncUtils.ErrorHandler> {
return [syncErrorHandler]
}
getCallbacks(registry: RelayerRegistry): Array<AsyncUtils.Callback> {
return [
(fromBlock: number, toBlock: number) => {
return registry.queryFilter(
registry.filters['RelayerRegistered(bytes32,string,address,uint256)'](null, null, null, null),
fromBlock,
toBlock
)
}
]
}
}
export class StakesCache extends Cache.Syncable<Stakes> {
// TODO: IMPLEMENT
buildDoc(response: any): Docs.Withdrawal {
return new Docs.Withdrawal(response)
}
getErrorHandlers(): Array<AsyncUtils.ErrorHandler> {
return [syncErrorHandler]
}
getCallbacks(registry: RelayerRegistry): Array<AsyncUtils.Callback> {
return [
(fromBlock: number, toBlock: number) => {
return registry.queryFilter(
registry.filters['StakeAddedToRelayer(address,uint256)'](null, null),
fromBlock,
toBlock
)
}
]
}
}
export class BurnsCache extends Cache.Syncable<Burns> {
// TODO: IMPLEMENT
buildDoc(response: any): Docs.Withdrawal {
return new Docs.Withdrawal(response)
}
getErrorHandlers(): Array<AsyncUtils.ErrorHandler> {
return [syncErrorHandler]
}
getCallbacks(registry: RelayerRegistry): Array<AsyncUtils.Callback> {
return [
(fromBlock: number, toBlock: number) => {
return registry.queryFilter(
registry.filters['StakeBurned(address,uint256)'](null, null),
fromBlock,
toBlock
)
}
]
}
}
export class Registry extends Synchronizer {
private _chain?: Chain
get chain(): Chain {
this._checkProvider('chain')
return this._chain!
}
constructor() {
super()
this.caches = new Map<string, Cache.Syncable<Docs.Base>>()
}
loadRegistrations(name: string, options?: Options.Cache): RegistrationsCache {
return this.loadCache<Registrations, RegistrationsCache>(name, options)
}
loadStakes(name: string, options?: Options.Cache): StakesCache {
return this.loadCache<Stakes, StakesCache>(name, options)
}
loadBurns(name: string, options?: Options.Cache): BurnsCache {
return this.loadCache<Burns, BurnsCache>(name, options)
}
loadCache<D extends Docs.Base, C extends Cache.Syncable<D> = Cache.Syncable<D>>(
name: string,
options?: Options.Cache
): C {
let constructor,
cache = super.loadCache(name)
if (!cache) {
const regexp = /([A-Za-z]+)([0-9]+)/
const matches = name.match(regexp)
if (!matches)
throw ErrorUtils.getError(`Registry.loadCache: name ${name} has wrong format for cache`)
// ETH net id
if (matches.length === 2)
name += "1"
if (matches[1] === 'Registrations') {
constructor = (name: string, options?: Options.Cache) => new RegistrationsCache(name, options)
} else if (matches[1] === 'Burns') {
constructor = (name: string, options?: Options.Cache) => new BurnsCache(name, options)
} else if (matches[1] === 'Stakes') {
constructor = (name: string, options?: Options.Cache) => new StakesCache(name, options)
} else throw ErrorUtils.getError(`Registry.loadCache: there exists no such event ${matches[1]}`)
cache = constructor(name, options)
this.caches.set(name, cache)
}
return cache as C
}
// TODO: FINISH
async _sync(
event: string,
networkId?: string,
options?: Merge<Options.Sync, Options.Cache>
): Promise<void> {
networkId = networkId ?? '1'
if (this.chain.id !== +networkId)
throw ErrorUtils.getError('Registry.syncRegistrations: provider bound to wrong chain!')
const registryAddress = await Onchain.getRegistryAddress(networkId)
options = options ?? {}
options.startBlock = options.startBlock ?? (await Onchain.getRegistryDeployBlockNum(networkId))
}
private _checkProvider(parentCallName: string): void {
if (!this._chain)
throw ErrorUtils.getError('Core.' + parentCallName + ': you must first connect a provider!')
}
protected async _populateSyncOptions(options: Options.Sync): Promise<DeepRequired<Options.Sync>> {
options.targetBlock = options.targetBlock ?? (await this.chain.latestBlockNum())
return super._populateSyncOptions(options)
}
}