2023.04.20: Check HISTORY.md for more info
Signed-off-by: T-Hax <>
This commit is contained in:
parent
d83dcd8112
commit
4b661dd3e6
11
HISTORY.md
11
HISTORY.md
@ -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
|
||||
)
|
||||
)
|
||||
|
194
src/lib/core.ts
194
src/lib/core.ts
@ -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 }
|
||||
|
110
src/lib/data.ts
110
src/lib/data.ts
@ -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 {
|
||||
|
1
src/resources/onchain/decimals.json
Normal file
1
src/resources/onchain/decimals.json
Normal file
@ -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}
|
66
src/resources/onchain/deployedBlockNumbers.json
Normal file
66
src/resources/onchain/deployedBlockNumbers.json
Normal file
@ -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
|
||||
}
|
66
src/resources/onchain/instanceAddresses.json
Normal file
66
src/resources/onchain/instanceAddresses.json
Normal file
@ -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"
|
||||
}
|
8
src/resources/onchain/networkSymbols.json
Normal file
8
src/resources/onchain/networkSymbols.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
1
src/resources/onchain/tokenAddresses.json
Normal file
1
src/resources/onchain/tokenAddresses.json
Normal file
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user