2023.04.18: Check HISTORY.md for more info

Signed-off-by: T-Hax <>
This commit is contained in:
T-Hax 2023-04-17 21:56:57 +00:00
parent 0a7c98abb9
commit d83dcd8112
21 changed files with 194720 additions and 519 deletions

1
.gitignore vendored
View File

@ -8,3 +8,4 @@ cache
.env
scripts
reference
.npm

View File

@ -1,4 +1,3 @@
build
node_modules
package-log.json
types/sol

View File

@ -1,5 +1,17 @@
# History
### 2023.04.18 (2023-04-18)
Did:
* Trying to test withdrawals. The issue is that the ganache provider seemingly can't provide data on events via queryFilter. Have manually inserted events, commitments seem to pass but the note is deemed invalid by the contract on forknet.
* Tests are more complicated right now, they rely on synchronized caches. Per default, all but that withdraw one should pass.
* The good news is, if we pass the withdraw test, then we almost have the hardest part done.
Next:
* Need to reorganize into monorepo.
### 2023.04.12 (2023-04-12)
Did:

View File

@ -10,7 +10,7 @@
"zk"
],
"private": false,
"version": "2023.04.12",
"version": "2023.04.18",
"engines": {
"node": "^18"
},
@ -29,7 +29,8 @@
"lint": "eslint --ext ts,js --fix src",
"format": "prettier src/lib/**/*.ts src/types/sdk/**/*.ts src/test/**/*.ts -w",
"build-live": "tsc -w && tsc-alias -w",
"typechain": "typechain --target \"ethers-v5\" --discriminate-types --glob \"./src/resources/abis/*.json\" --out-dir=\"./src/types/deth\""
"typechain": "typechain --target \"ethers-v5\" --discriminate-types --glob \"./src/resources/abis/*.json\" --out-dir=\"./src/types/deth\"",
"clean": "rm -rf --interactive=never cache/*"
},
"license": "ISC",
"dependencies": {
@ -74,6 +75,6 @@
"tsc-alias": "^1.2.11",
"tsconfig-paths": "^4.1.2",
"typechain": "^8.1.1",
"typescript": "^5.1.0-dev.20230310"
"typescript": "^5"
}
}

View File

@ -3,4 +3,4 @@ export * as Data from "lib/data"
export * as Network from "lib/chain"
export * as Web from "lib/web"
export * as Utils from "lib/utils"
export * from "lib/main"
export * from "lib/core"

View File

@ -1,12 +1,7 @@
// Tooling for interaction with the blockchain.
// Types
import { MarkOptional } from 'ts-essentials'
import * as Types from 'types/sdk/chain'
// External imports
import { TransactionRequest } from '@ethersproject/abstract-provider'
import { BaseContract, BigNumber, ContractTransaction, providers, Signer, VoidSigner } from 'ethers'
import { randomBytes } from 'crypto'
// Our local types
import {
ERC20Tornado__factory,
@ -21,19 +16,19 @@ import {
} from 'types/deth'
import { Multicall3 } from 'types/deth/Multicall3Contract'
// External imports
import { TransactionRequest } from '@ethersproject/abstract-provider'
import { BaseContract, BigNumber, ContractTransaction, providers, Signer, VoidSigner } from 'ethers'
import { randomBytes } from 'crypto'
// Local modules
import { OnchainData } from 'lib/data'
import { ErrorUtils } from './utils'
import { MarkOptional } from 'ts-essentials'
import { ErrorUtils, HexUtils } from 'lib/utils'
// We use a vanilla provider here, but in reality we will probably
// add a censorship-checking custom derivative of it
type Provider = providers.Provider
export function prepareAddress(address: string): string {
return (address.slice(0, 2) == '0x' ? address.slice(2) : address).toLowerCase().padStart(64, '0')
}
/**
* The Chain class stores Tornado-agnostic chain data and also
* handles such interactions.
@ -43,6 +38,7 @@ export class Chain {
public provider: Provider
private _emptySigner: VoidSigner
public chainId?: number
public symbol?: string
constructor(provider: Provider, signer?: Signer) {
this.provider = provider
@ -55,14 +51,27 @@ export class Chain {
return this.chainId
}
async latestBlockNum(): Promise<number> {
async getChainSymbol(): Promise<string> {
if (!this.symbol) this.symbol = await OnchainData.getNetworkSymbol(String(await this.getChainId()))
return this.symbol
}
latestBlockNum(): Promise<number> {
return this.provider.getBlockNumber()
}
async getAccountBalance(account: string): Promise<BigNumber> {
getAccountBalance(account: string): Promise<BigNumber> {
return this.provider.getBalance(account)
}
getGasPrice(): Promise<BigNumber> {
return this.provider.getGasPrice()
}
getTokenContract(tokenAddress: string): ERC20 {
return Contracts.getToken(tokenAddress, this.signer ?? this.provider)
}
async getTokenDecimals(token: string): Promise<BigNumber> {
let treq = {
to: token,
@ -74,16 +83,12 @@ export class Chain {
async getTokenBalance(account: string, token: string, normalized: boolean = false): Promise<BigNumber> {
let treq = {
to: token,
data: '0x70a08231000000000000000000000000' + prepareAddress(account)
data: '0x70a08231000000000000000000000000' + HexUtils.prepareAddress(account)
}
let divisor = normalized ? BigNumber.from(10).pow(await this.getTokenDecimals(token)) : 1
return BigNumber.from(await this._emptySigner.call(treq)).div(divisor)
}
getTokenContract(tokenAddress: string): ERC20 {
return ERC20__factory.connect(tokenAddress, this.provider)
}
async populateBatchCall(
callStruct: Array<MarkOptional<Multicall3.Call3ValueStruct, 'value'>>
): Promise<TransactionRequest> {
@ -181,7 +186,13 @@ export namespace Contracts {
return contractMap.get(key) as TornadoInstance
}
export async function getTornToken(signerOrProvider: Signer | Provider): Promise<ERC20> {
export function getToken(tokenAddress: string, signerOrProvider: Signer | Provider): ERC20 {
if (!contractMap.has(tokenAddress))
contractMap.set(tokenAddress, _getContract<ERC20>('ERC20', tokenAddress, signerOrProvider))
return contractMap.get(tokenAddress) as ERC20
}
export function getTornToken(signerOrProvider: Signer | Provider): ERC20 {
const key = '$TORN'
if (!contractMap.has(key)) {
contractMap.set(

View File

@ -1,37 +1,41 @@
// ts-essentials
import { DeepRequired } from 'ts-essentials'
import { DeepRequired, MarkOptional, MarkRequired } from 'ts-essentials'
// Local types
import { RelayerProperties } from 'types/sdk/data'
import { Options, Transactions } from 'types/sdk/main'
import { RelayerProperties as RelayerDataProperties } from 'types/sdk/data'
import { Options, Transactions } from 'types/sdk/core'
import { ZKDepositData, InputFor } from 'types/sdk/crypto'
import { TornadoInstance, TornadoProxy } from 'types/deth'
// External imports
import { BigNumber, EventFilter, providers } from 'ethers'
import { parseUnits } from 'ethers/lib/utils'
import { bigInt } from 'snarkjs'
// @ts-ignore
import { parseIndexableString } from 'pouchdb-collate'
// Important local
import { Docs, Cache, Types as DataTypes, Json, Constants } from 'lib/data'
// Local imports
import { Docs, Cache, Types as DataTypes, Json, Constants, OnchainData } from 'lib/data'
import { Primitives } from 'lib/crypto'
import { Contracts } from 'lib/chain'
// Other local imports
import { OnchainData } from 'lib/data'
import { ErrorUtils } from 'lib/utils'
import { Chain } from 'lib/chain'
import { parseUnits } from 'ethers/lib/utils'
import { Contracts, Chain } from 'lib/chain'
import { ErrorUtils, ObjectUtils } from 'lib/utils'
type Provider = providers.Provider
type BackupDepositDoc = {
pathstring: string
network: string
denomination: string
token: string
invoice?: string
note?: string
}
type RelayerProperties = MarkOptional<
Pick<RelayerDataProperties, 'address' | 'serviceFeePercent' | 'prices'>,
'serviceFeePercent' | 'prices'
>
export class Core {
chain: Chain
caches: Map<string, Cache.Base<Docs.Base>>
@ -39,7 +43,7 @@ export class Core {
constructor(provider: providers.Provider) {
this.chain = new Chain(provider)
this.caches = new Map<string, Cache.Base<Docs.Base>>()
this.caches = new Map<string, Cache.Syncable<Docs.Base>>()
this.instances = new Map<string, TornadoInstance>()
}
@ -65,7 +69,7 @@ export class Core {
async getProxy(): Promise<TornadoProxy> {
const chainId = await this.chain.getChainId()
return Contracts.getProxy(String(chainId), this.chain.signer ?? this.chain.provider)
return Contracts.getProxy(String(chainId), this.chain.provider)
}
async buildDepositProof(
@ -74,7 +78,7 @@ export class Core {
recipientAddress: string,
zkDepositsData: ZKDepositData,
options?: Options.Core.BuildDepositProof
): Promise<any> {
): Promise<Array<string>> {
return (
await this.buildDepositProofs(
instance,
@ -88,10 +92,10 @@ export class Core {
/**
* @param instance This is the Tornado Instance which will be withdrawn from.
* @param relayerProperties The properties of the relayer that is going to be used for the withdrawals. These properties are included in the ZK proof.
* @param relayerProperties The properties of the relayer that is going to be used for the withdrawals. If the service fee is 0, it is assumed that there is no relayer, but that a manual wallet withdraw is being made. These properties are included in the ZK proof.
* @param recipientAddresses The recipient addresses which should receive the withdrawals, in order.
* @param zkDepositsData These represent the public and private values, reconstructed from the deposit note, generated during the building of deposit transactions, used for building the proof of knowledge statement for withdrawal, for each withdrawal (in this context).
* @param options Additional options which allow the user to skip checking whether the notes are spent or changing the target merkle tree height.
* @param options Numerous options which most importantly allow a user to specify whether he is buying ETH, whether to check proof data validity and finally to modulate the gas prices which will be used to calculate the gas fees paid to the relayer.
* @returns The proofs for which the user should then decide whether to use a relayer (recommended, but decide carefully which one) or use his own wallet (if needed).
*/
async buildDepositProofs(
@ -100,16 +104,19 @@ export class Core {
recipientAddresses: Array<string>,
zkDepositsData: Array<ZKDepositData>,
options?: Options.Core.BuildDepositProof
): Promise<Array<any>> {
): Promise<Array<Array<string>>> {
// Extract commitments and nullifier hashes
const hexCommitments: string[] = []
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.'
)
if (zkDepositsData.length !== purchaseAmounts.length)
throw ErrorUtils.getError(
'Core.buildDepositProofs: if purchase amounts is specified, it must equal the length of zkDepositsData.'
@ -120,20 +127,26 @@ export class Core {
hexNullifierHashes.push(deposit.hexNullifierHash)
})
console.log('\nGetting lookup keys.\n')
// Determine cache name
const lookupKeys = await this.getInstanceLookupKeys(instance.address)
const name = 'Deposit' + (lookupKeys.network + lookupKeys.token + lookupKeys.denomination).toUpperCase()
const name = 'Deposits' + (lookupKeys.network + lookupKeys.token + lookupKeys.denomination).toUpperCase()
// Find all leaf indices by reading from cache
const leafIndices = await this._findLeafIndices(name, hexCommitments)
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[] = []
// Determine whether we will be checking whether notes are spent
const spentNotes: string[] = []
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) : null
const checkSpentArray = checkSpent ? await instance.isSpentArray(hexNullifierHashes) : undefined
// Check whether a commitment has not been found in all deposits, meaning that it is invalid
// Also add the invalid commitments. We can do leafIndices[i] because the matched one are concatenated
@ -148,37 +161,65 @@ export class Core {
const commitmentsAreInvalid = invalidCommitments.length !== 0
const notesAreSpent = spentNotes.length !== 0
console.log('\nErrors.\n')
if (commitmentsAreInvalid || notesAreSpent)
throw ErrorUtils.getError(
`Core.buildWithdrawalTxs: ` +
`Core.buildDepositProofs: ` +
(commitmentsAreInvalid
? `following commitments are invalid:\n\n${invalidCommitments.join('\n')}\n\n`
: '') +
(notesAreSpent
? `${commitmentsAreInvalid ? 'and ' : ''}following notes are already spent:\n\n${spentNotes.join(
'\n'
)}\n\n`
? `${
commitmentsAreInvalid ? 'and ' : ''
}following notes are already spent or invalid:\n\n${spentNotes.join('\n')}\n\n`
: '')
)
// Otherwise, build the merkle tree from the leaf indices
// We have to slice to get the leaf indices in order
console.log('\nMerkle tree.\n')
// Otherwise, build the merkle tree from the leaves
const merkleTree = Primitives.buildMerkleTree({
height: options?.merkleTreeHeight ?? Constants.MERKLE_TREE_HEIGHT,
leaves: leafIndices.slice(zkDepositsData.length).map((leafIndex) => String(leafIndex))
leaves: leaves
})
const root: string = merkleTree.root()
const checkKnownRoot: boolean = options?.checkKnownRoot ?? true
// Check whether the root is valid
if (!(await instance.isKnownRoot(root)))
if (checkKnownRoot && !(await instance.isKnownRoot(root)))
throw ErrorUtils.getError(
'Core.buildWithdrawalTxs: the merkle tree created is not valid, something went wrong with syncing.'
'Core.buildDepositProofs: the merkle tree created is not valid, something went wrong with syncing.'
)
// Compute proofs
const inputsForProofs: InputFor.ZKProof[] = []
console.log('\nProof data invariant.\n')
// Rest of note invariant arguments
const inputsForProofs: InputFor.ZKProof[] = []
const gasPrice = options?.gasPrice ?? (await this.chain.getGasPrice())
const gasPriceCushion = options?.gasPrice ?? gasPrice.mul(10).div(100)
// In reality, if a manual withdraw is made, we don't differentiate it from a relayer withdraw
// Since it is only serviceFee 0 AND without a token price, the function will not buy more tokens
const serviceFee = relayerProperties.serviceFeePercent ?? 0
const tokenPrice = relayerProperties.prices?.get(lookupKeys.token)
const decimals =
// @ts-expect-error
bigInt(10).pow(
options?.tokenDecimals ?? (await OnchainData.getTokenDecimals(lookupKeys.network, lookupKeys.token))
)
const toWithdraw = BigNumber.from(lookupKeys.denomination).mul(decimals)
// TODO: Decide if necessary
if (!tokenPrice && lookupKeys.token !== (await this.chain.getChainSymbol()))
throw ErrorUtils.getError(
'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({
public: {
@ -188,8 +229,17 @@ export class Core {
hexNullifierHash: zkDepositsData[i].hexNullifierHash,
recipientAddress: recipientAddresses[i],
relayerAddress: relayerProperties.address,
fee: 5, // TODO: placeholder
refund: purchaseAmounts[i] ?? 0
fee: this._calcWithdrawalFee(
toWithdraw,
decimals,
gasPrice,
gasPriceCushion,
serviceFee,
purchaseAmounts[i],
tokenPrice
),
// @ts-expect-error
refund: bigInt(purchaseAmounts[i].toString()) ?? bigInt(0)
},
private: {
nullifier: zkDepositsData[i].nullifier,
@ -198,9 +248,68 @@ export class Core {
})
}
console.log('\nCalc and return.\n')
return await Primitives.calcDepositProofs(inputsForProofs)
}
private _calcWithdrawalFee(
toWithdraw: BigNumber,
decimals: BigNumber,
gasPrice: BigNumber,
gasPriceCushion: BigNumber,
relayerServiceFee: number,
ethBought?: BigNumber,
tokenPriceInEth?: BigNumber
): typeof bigInt {
const factor = BigNumber.from(10).pow(String(relayerServiceFee).length)
const baseRelayerFee = toWithdraw.mul(BigNumber.from(relayerServiceFee).mul(factor)).div(factor)
const txCost = gasPrice.add(gasPriceCushion).mul(5e5)
if (ethBought && tokenPriceInEth) {
// @ts-expect-error
return bigInt(txCost.add(ethBought).mul(decimals).div(tokenPriceInEth).add(baseRelayerFee).toString())
}
// @ts-expect-error
else return bigInt(txCost.add(baseRelayerFee).toString())
}
async loadNotes(
indexes?: Array<number>,
keys?: Partial<DataTypes.Keys.InstanceLookup>
): Promise<Array<ZKDepositData>> {
const rows = await Cache.loadContents<Docs.Note>('DepositNotes')
let docs: Array<Docs.Note | undefined> = []
let notes: Array<string> = []
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)
}
else docs = rows.map((row) => row.doc)
if (keys)
docs.forEach((doc) => {
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)
if (lastlyDenominationMatches && doc?.note) notes.push(doc.note)
})
else notes = docs.filter((doc) => ObjectUtils.exists(doc?.note)).map((doc) => doc!.note)
return this.parseNotes(notes)
}
parseNotes(notes: Array<string>): Array<ZKDepositData> {
return notes.map((note) => Primitives.parseNote(note))
}
parseNote(note: string): ZKDepositData {
return this.parseNotes([note])[0]
}
async createInvoice(
instance: TornadoInstance,
options?: Omit<Options.Core.Invoice, 'depositsPerInstance'>
@ -261,9 +370,21 @@ export class Core {
const deposit = Primitives.createDeposit()
const note = Primitives.createNote(deposit.preimage)
if (backupNotes) notesToBackup.push({ pathstring: pathstring, note: note })
if (backupNotes)
notesToBackup.push({
network: lookupKeys.network,
denomination: lookupKeys.denomination,
token: lookupKeys.token,
note: note
})
if (backupInvoices) invoicesToBackup.push({ pathstring: pathstring, invoice: deposit.hexCommitment })
if (backupInvoices)
invoicesToBackup.push({
network: lookupKeys.network,
denomination: lookupKeys.denomination,
token: lookupKeys.token,
invoice: deposit.hexCommitment
})
if (!doNotPopulate) {
txs.push({
@ -305,8 +426,10 @@ export class Core {
await cache.db
.bulkDocs(
backupData.map((entry) => {
if (entry.note) return new Docs.Note(++id, entry.pathstring, entry.note)
else if (entry.invoice) return new Docs.Invoice(++id, entry.pathstring, entry.invoice)
if (entry.note)
return new Docs.Note(++id, entry.network, entry.token, entry.denomination, entry.note)
else if (entry.invoice)
return new Docs.Invoice(++id, entry.network, entry.token, entry.denomination, entry.invoice)
}) as Array<T>
)
.catch((err) => {
@ -318,6 +441,13 @@ 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))
}
return this.caches.get(cacheName) as C
}
async syncMultiple(instances: Array<TornadoInstance>, syncOptions?: Options.Core.Sync): Promise<void> {
for (const instance of instances) {
await this.sync(instance, syncOptions)
@ -350,21 +480,41 @@ export class Core {
}`,
pathstring = name.substring(action.length).toLowerCase()
let cache: Cache.Syncable<Docs.Base>, toDoc: (_: any) => Docs.Base, filter: EventFilter
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 = new Cache.Deposit(name, syncOptions.cache)
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 = new Cache.Withdrawal(name, syncOptions.cache)
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))
// Decide whether we have a latest block
numEntries = (await cache.db.info()).doc_count
// Check for synced blocks
if (0 < numEntries) {
const [lastSyncedBlock, ,] = parseIndexableString(
(await cache.db.allDocs({ descending: true, limit: 1 })).rows[0].id
)
syncOptions.blocks.startBlock =
lastSyncedBlock < syncOptions.blocks.startBlock ? syncOptions.blocks.startBlock : lastSyncedBlock
syncOptions.blocks.blockDelta = this._getBlockDelta(syncOptions)
}
// Start synchronizing
let dbPromises = []
@ -373,14 +523,14 @@ export class Core {
blockDelta = syncOptions.blocks.blockDelta,
targetBlock = syncOptions.blocks.targetBlock,
concurrencyLimit = syncOptions.cache.sync.concurrencyLimit;
currentBlock < targetBlock + blockDelta;
currentBlock < targetBlock;
currentBlock += blockDelta
) {
if (cache.sync.pooler.pending < concurrencyLimit) {
if (currentBlock < targetBlock) {
await cache.sync.pooler.pool(currentBlock, currentBlock + blockDelta)
const sum = currentBlock + blockDelta
if (currentBlock + blockDelta < targetBlock) {
await cache.sync.pooler.pool(currentBlock, sum)
} else {
let sum = currentBlock + blockDelta
await cache.sync.pooler.pool(currentBlock, sum - (sum % targetBlock))
}
} else {
@ -452,8 +602,7 @@ export class Core {
syncOptions.blocks.targetBlock = syncOptions.blocks.targetBlock ?? (await this.chain.latestBlockNum())
syncOptions.blocks.blockDelta =
syncOptions.blocks.blockDelta ?? (syncOptions.blocks.targetBlock - syncOptions.blocks.startBlock) / 20
syncOptions.blocks.blockDelta = this._getBlockDelta(syncOptions)
// cache
// db
@ -467,14 +616,24 @@ export class Core {
return syncOptions as DeepRequired<Options.Core.Sync>
}
private _getBlockDelta(syncOptions?: Options.Core.Sync): number {
return Math.floor(
syncOptions?.blocks?.blockDelta ??
(syncOptions!.blocks!.targetBlock! - syncOptions!.blocks!.startBlock!) / 20
)
}
/**
* @param instanceName The name of the instance as created in `_sync` function.
* @param commitments The commitments for which the leaf index values are to be noted down extra.
* @returns The result of concatenating the array of leaf indices found by matching them with the provided commitment values, followed by the array of all leaf indices, including all of the formerly mentioned values given that they are valid. Values which have not been matched, meaning probably invalid values, will be `0`.
*/
private async _findLeafIndices(instanceName: string, commitments: Array<string>): Promise<Array<number>> {
const matchedLeafIndices = new Array<number>(commitments.length).fill(0)
const leafIndices: Array<number> = []
private async _findLeavesAndIndices(
instanceName: string,
commitments: Array<string>
): Promise<[Array<string>, Array<number>]> {
const indices = new Array<number>(commitments.length).fill(0)
const leaves: Array<string> = []
// Either load all deposit events from memory or from cache
let cache: Cache.Base<Docs.Deposit>
@ -493,24 +652,23 @@ export class Core {
)
}
// Otherwise start looking for commitment leaf indices and also pick up
// all other leafs on the way
// Otherwise start looking for commitment leaf indices and also pick up all other leafs on the way
for (const row of docs.rows) {
const [, leafIndex, loadedCommitment] = parseIndexableString(row.id)
const index = commitments.findIndex((commitment) => commitment === loadedCommitment)
// If some commitment is found then add the leaf index and remove that commitment
if (index !== -1) {
matchedLeafIndices[index] = leafIndex
indices[index] = leafIndex
commitments.splice(index, 1)
}
// In any case push every leaf
leafIndices.push(leafIndex)
leaves.push(BigNumber.from(loadedCommitment).toString())
}
// Concat matched and all leaf indices
return matchedLeafIndices.concat(leafIndices)
return [leaves, indices]
}
async getInstanceLookupKeys(instanceAddress: string): Promise<DataTypes.Keys.InstanceLookup> {
@ -521,7 +679,6 @@ export class Core {
const pathstring: string = Object.entries(lookupObj).find((el) => el[1] === instanceAddress)![0]
// I like JS/TS
const network = pathstring.match('[0-9]+')![0],
token = pathstring.substring(network.length).match('[a-z]+')![0],
denomination = pathstring.substring(network.length + token.length)

View File

@ -50,7 +50,8 @@ export namespace Primitives {
}
export function parseNote(hexNote: string): Types.ZKDepositData {
const buffer = Buffer.from(hexNote, 'hex')
const _hexNote = hexNote.split('_')[1] ?? hexNote
const buffer = Buffer.from(_hexNote, 'hex')
return createDeposit({
// @ts-expect-error
nullifier: bigInt.leBuff2int(buffer.subarray(0, 31)),
@ -66,11 +67,11 @@ export namespace Primitives {
secret: NumberUtils.randomBigInteger(31)
}
// @ts-expect-error
let preimage = Buffer.concat([depositData.nullifier.leInt2Buff(31), depositData.secret.leInt2Buff(31)])
let preimage = Buffer.concat([input.nullifier.leInt2Buff(31), input.secret.leInt2Buff(31)])
let commitment = calcPedersenHash({ msg: preimage })
let commitmentHex = HexUtils.bigIntToHex(commitment)
// @ts-expect-error
let nullifierHash = calcPedersenHash({ msg: depositData.nullifier.leInt2Buff(31) })
let nullifierHash = calcPedersenHash({ msg: input.nullifier.leInt2Buff(31) })
let nullifierHex = HexUtils.bigIntToHex(nullifierHash)
return {
nullifier: input.nullifier!,
@ -87,10 +88,10 @@ export namespace Primitives {
return new MerkleTree(inputs.height, inputs.leaves)
}
export async function calcDepositProofs(inputs: Array<Types.InputFor.ZKProof>): Promise<Array<any>> {
export async function calcDepositProofs(
inputs: Array<Types.InputFor.ZKProof>
): Promise<Array<Array<string>>> {
const proofs: string[][] = []
const args: any[][] = []
const groth16 = await Setup.getGroth16()
const circuit = await Setup.getTornadoCircuit()
const provingKey = await Setup.getProvingKey()
@ -101,7 +102,6 @@ export namespace Primitives {
// Compute Merkle Proof
const { pathElements, pathIndex } = input.public.tree.path(input.public.leafIndex)
args.push([])
proofs.push([])
const proofData = await genWitnessAndProve(
@ -109,16 +109,16 @@ export namespace Primitives {
{
// Public inputs
root: input.public.root,
// @ts-ignore
// @ts-expect-error
nullifierHash: bigInt(input.public.hexNullifierHash),
// @ts-ignore
fee: bigInt(input.public.fee),
// @ts-ignore
refund: bigInt(input.public.refund),
// @ts-ignore
relayer: bigInt(input.public.relayerAddress),
// @ts-ignore
// @ts-expect-error
recipient: bigInt(input.public.recipientAddress),
// @ts-expect-error
relayer: bigInt(input.public.relayerAddress),
// @ts-expect-error
fee: bigInt(input.public.fee),
//
refund: input.public.refund,
// Private inputs
nullifier: input.private.nullifier,
@ -132,21 +132,20 @@ export namespace Primitives {
proofs[i].push(toSolidityInput(proofData).proof)
args[i].push([
proofs[i].push(
input.public.root,
input.public.hexNullifierHash,
HexUtils.prepareAddress(input.public.recipientAddress, 20),
// @ts-ignore
HexUtils.prepareAddress(input.public.relayerAddress, 20),
HexUtils.numberToHex(input.public.fee),
HexUtils.numberToHex(input.public.refund)
])
'0x' + HexUtils.prepareAddress(input.public.recipientAddress, 20),
'0x' + HexUtils.prepareAddress(input.public.relayerAddress, 20),
HexUtils.bigIntToHex(input.public.fee),
HexUtils.bigIntToHex(input.public.refund)
)
}
// Done. 🤷‍♀️
groth16.terminate()
return proofs.concat(args)
return proofs
}
}

View File

@ -2,11 +2,7 @@
import { TornadoInstance } from 'types/deth'
import * as Types from 'types/sdk/data'
import { RelayerProperties } from 'types/sdk/data'
import { Options } from 'types/sdk/main'
// Local logic
import { NumberUtils, ErrorUtils } from 'lib/utils'
import { AsyncUtils } from 'lib/utils'
import { Options } from 'types/sdk/core'
// Big modules
import { BigNumber } from 'ethers'
@ -14,13 +10,15 @@ import { existsSync, mkdirSync } from 'fs'
import { opendir, readFile, rm } from 'fs/promises'
import { createInterface } from 'readline'
// Local logic
import { AsyncUtils, NumberUtils, ErrorUtils } from 'lib/utils'
// PouchDB
import PouchDB from 'pouchdb'
import * as PouchDBAdapterMemory from 'pouchdb-adapter-memory'
// @ts-ignore
import { toIndexableString } from 'pouchdb-collate'
import { timeStamp } from 'console'
// Register plugins
PouchDB.plugin(PouchDBAdapterMemory)
@ -146,20 +144,24 @@ export namespace OnchainData {
export async function getInstanceAttrSet<T>(
key: string,
paths: Array<{
network: string
token: string
denomination: string
network?: string
token?: string
denomination?: string
}>
): Promise<Array<T>> {
const obj = await Json.load('onchain/quickLookup.json')
return await Promise.all(
paths.map((path) => Json.getValue(obj, [key, `${path.network}${path.token}${path.denomination}`]))
paths.map((path) =>
Json.getValue(obj, [key, `${path.network ?? '\0'}${path.token ?? '\0'}${path.denomination ?? '\0'}`])
)
)
}
// TODO: Add field key for classic or nova
export async function getNetworkSymbol(networkId: string): Promise<string> {
return (await getInstanceAttrSet<string>('networkSymbols', [{ network: networkId }]))[0]
}
export async function getInstanceAddresses(
export function getInstanceAddresses(
paths: Array<{
network: string
token: string
@ -177,7 +179,7 @@ export namespace OnchainData {
return (await getInstanceAddresses([{ network: network, token: token, denomination: denomination }]))[0]
}
export async function getInstanceDeployBlockNums(
export function getInstanceDeployBlockNums(
paths: Array<{
network: string
token: string
@ -217,6 +219,10 @@ export namespace OnchainData {
address: data['address']
}
}
export async function getTokenDecimals(network: string, token: string): Promise<number> {
return (await getTokenData(network, token)).decimals
}
}
export namespace OffchainData {
@ -307,23 +313,31 @@ export namespace Docs {
}
export class Note extends Base {
pathstring: string
network: string
token: string
denomination: string
note: string
constructor(index: number, pathstring: string, note: string) {
super(toIndexableString([index, pathstring]))
this.pathstring = pathstring
constructor(index: number, network: string, token: string, denomination: string, note: string) {
super(toIndexableString([index, network, denomination, token]))
this.network = network
this.token = token
this.denomination = denomination
this.note = note
}
}
export class Invoice extends Base {
pathstring: string
network: string
token: string
denomination: string
invoice: string
constructor(index: number, pathstring: string, invoice: string) {
super(toIndexableString([index, pathstring]))
this.pathstring = pathstring
constructor(index: number, network: string, token: string, denomination: string, invoice: string) {
super(toIndexableString([index, network, denomination, token]))
this.network = network
this.token = token
this.denomination = denomination
this.invoice = invoice
}
}
@ -335,6 +349,7 @@ export namespace Docs {
miningFeePercent: number
status: string
chainId: number
prices: Map<string, BigNumber>
constructor(url: string, properties: RelayerProperties) {
super(toIndexableString([url]))
@ -344,6 +359,7 @@ export namespace Docs {
this.miningFeePercent = properties.miningFeePercent
this.status = properties.status
this.chainId = properties.chainId
this.prices = properties.prices
}
}
}
@ -354,10 +370,10 @@ export namespace Cache {
constructor(name: string, options?: Options.Cache.Database) {
if (options?.persistent === false && options?.adapter !== 'memory' && options?.adapter !== null)
throw ErrorUtils.getError('if not persistent, cache must use memory adapter.')
throw ErrorUtils.getError('Cache.new: if not persistent, cache must use memory adapter.')
if (options?.adapter === 'memory' && options?.persistent === true)
throw ErrorUtils.getError("can't specify memory adapter if persistent.")
throw ErrorUtils.getError("Cache.new: can't specify memory adapter if persistent.")
const dbAdapter = options?.adapter ?? (options?.persistent === false ? 'memory' : 'leveldb')
@ -392,13 +408,13 @@ export namespace Cache {
async close(): Promise<void> {
if (this.sync.pooler!.pending)
throw ErrorUtils.getError("can't clear while pooler still has pending promises.")
throw ErrorUtils.getError("Syncable.close: can't clear while pooler still has pending promises.")
await super.close()
}
async clear(): Promise<void> {
if (this.sync.pooler!.pending)
throw ErrorUtils.getError("can't clear while pooler still has pending promises.")
throw ErrorUtils.getError("Syncable.clear: can't clear while pooler still has pending promises.")
await super.clear()
}
}
@ -440,13 +456,16 @@ export namespace Cache {
`Core.loadCacheContents: there is no cache entry for ${nameOfContent}`
)
): Promise<DocsArray<T>> {
const cache = new Cache.Base<T>(Files.getCachePath(nameOfContent))
const cache = new Cache.Base<T>(nameOfContent)
const docs = await cache.db.allDocs({ include_docs: full }).catch((err) => {
throw ErrorUtils.ensureError(err)
})
if (docs.total_rows === 0) throw emptyError
if (docs.total_rows === 0) {
await cache.clear()
throw emptyError
}
return docs.rows as DocsArray<T>
}

View File

@ -1,6 +1,6 @@
// Local types
import * as Crypto from 'types/sdk/crypto'
import { Options } from 'types/sdk/main'
import { Options } from 'types/sdk/core'
// Needed
import { BigNumber } from 'ethers'
@ -8,8 +8,8 @@ import { bigInt } from 'snarkjs'
import { randomBytes } from 'crypto'
export namespace ErrorUtils {
export function ensureError(value: unknown): Error {
if (value instanceof Error) return value
export function ensureError<T extends Error>(value: unknown): T {
if (value instanceof Error) return value as T
let stringified = '[Unable to stringify the thrown value]'
try {
@ -17,7 +17,7 @@ export namespace ErrorUtils {
} catch {}
const error = getError(`This value was thrown as is, not through an Error: ${stringified}`)
return error
return error as T
}
export function getError(message: string): Error {
@ -177,13 +177,9 @@ export namespace NumberUtils {
isInteger: number = 1
): number {
isInteger = 0 < isInteger ? 1 : 0
return (
isInteger
? Math.floor
: (x: number) => {
return x
}
)(Math.random() * (upperInclusive + isInteger - lowerInclusive) + lowerInclusive)
return (isInteger ? Math.floor : (x: number) => x)(
Math.random() * (upperInclusive + isInteger - lowerInclusive) + lowerInclusive
)
}
}
@ -240,4 +236,8 @@ export namespace ObjectUtils {
right: left
}
}
export function exists(obj: any): boolean {
return obj !== undefined && obj !== null
}
}

View File

@ -1,34 +1,46 @@
import axios from 'axios'
import { AxiosInstance } from 'axios'
import { SocksProxyAgent } from 'socks-proxy-agent'
import { Web3Provider, Networkish } from '@ethersproject/providers'
import { RelayerOptions } from 'types/sdk/web'
import { BigNumber } from 'ethers'
import { ErrorUtils } from './utils'
import { Cache, Docs } from './data'
// Types
import { Relayer as Types, RelayerOptions } from 'types/sdk/web'
import { RelayerProperties } from 'types/sdk/data'
// HTTP and proxy
import axios from 'axios'
import { AxiosInstance, AxiosError, AxiosResponse } from 'axios'
import { SocksProxyAgent } from 'socks-proxy-agent'
// Ethers
import { BigNumber } from 'ethers'
import { Web3Provider, Networkish } from '@ethersproject/providers'
// Local
import { ErrorUtils } from 'lib/utils'
import { Cache, Docs } from 'lib/data'
// It seems that the default HttpProvider offered by the normal web3 package
// has some logic which either ignores the SocksProxyAgent or which falls back to
// using no proxy for some reason. In any case, the Tornado-modified one, originally
// modified by the Tornado Team or who else, seems to properly error out when Tor
// is not running.
// modified by the Tornado Team or whoever else conributed, seems to properly error
// out when Tor is not running.
const HttpProvider = require('web3-providers-http')
export interface TorOptions {
export interface ObfuscationOptions {
port?: number
headers?: { name: string; value: string }[]
rv?: string
}
/**
* You can also set up a SOCKS5 I2P tunnel on some port and then use that instead. Meaning that this should be compatible with I2P.
*/
export class TorProvider extends Web3Provider {
constructor(url: string, torOpts: TorOptions, network?: Networkish) {
constructor(url: string, torOpts?: ObfuscationOptions, network?: Networkish) {
torOpts = torOpts ?? {}
torOpts.rv = torOpts.rv ?? '102.0'
const torPort = torOpts.port ?? 9050,
headers = torOpts.headers ?? [
{ name: 'User-Agent', value: 'Mozilla/5.0 (Windows NT 10.0; rv:102.0) Gecko/20100101 Firefox/102.0' }
{
name: 'User-Agent',
value: `Mozilla/5.0 (Windows NT 10.0; rv:${torOpts.rv}) Gecko/20100101 Firefox/${torOpts.rv}`
}
]
super(
@ -79,8 +91,9 @@ export class Relayer {
private _miningFee?: number
private _status?: string
private _chainId?: number
private _prices?: Map<string, BigNumber>
constructor(options: RelayerOptions, properties?: RelayerProperties) {
constructor(options: Types.Options, properties?: RelayerProperties) {
this.url = options.url
this.httpClient = options.httpClient
this._fetched = false
@ -92,6 +105,7 @@ export class Relayer {
this._serviceFee = properties.serviceFeePercent
this._miningFee = properties.miningFeePercent
this._status = properties.status
this._prices = properties.prices
this._fetched = true
}
}
@ -121,6 +135,10 @@ 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 {
@ -129,7 +147,8 @@ export class Relayer {
chainId: this._chainId!,
serviceFeePercent: this._serviceFee!,
miningFeePercent: this._miningFee!,
status: this._status!
status: this._status!,
prices: this._prices!
}
}
@ -166,6 +185,10 @@ export class Relayer {
this._propertiesFetched('chainId')
return this._chainId!
}
get prices(): Map<string, BigNumber> {
this._propertiesFetched('prices')
return this._prices!
}
async getETHPurchasePrice(token: string): Promise<BigNumber> {
return BigNumber.from(
@ -178,13 +201,60 @@ export class Relayer {
)
}
// TODO: Relaying stuff and related
async handleWithdrawal(
instanceAddress: string,
proof: Array<string>
): Promise<Types.WithdrawalRequestResult> {
const response = (await this.httpClient
.post(this.url + '/v1/tornadoWithdraw', {
contract: instanceAddress,
proof: proof[0],
args: proof.slice(1)
})
.catch(this._handleHTTPError)) as AxiosResponse
async relay(): Promise<any> {}
const { id } = response.data
async calcWithdrawalFee(token: string, denomination: number): Promise<BigNumber> {
//placeholder
return BigNumber.from(0)
let result: Types.WithdrawalRequestResult = { success: false },
finished = false
while (!finished) {
const statusResponse = (await this.httpClient
.get(this.url + '/v1/jobs/' + id)
.catch((err) => this._handleHTTPError(err, false))) as AxiosResponse
if (statusResponse.status === 200) {
const { txHash, status, _, failedReason } = statusResponse.data
if (status === 'FAILED') {
console.error(`\nRelayer.handleWithdrawal: withdrawal failed with reason: ${failedReason}\n`)
finished = true
}
if (status == 'CONFIRMED') {
result.success = true
result.txHash = txHash
finished = true
}
}
await new Promise((resolve) => setTimeout(resolve, 3000))
}
return result
}
private _handleHTTPError(err: AxiosError, httpThrow: boolean = true): void {
err = ErrorUtils.ensureError(err)
if (err.response) {
if (httpThrow)
// @ts-expect-error
throw ErrorUtils.ensureError(err.response.data.error)
// @ts-expect-error
else console.error(err.response.data.error)
} else if (err.request) {
if (httpThrow) throw ErrorUtils.ensureError(err.request)
else console.error(err.request)
} else throw err
}
// Cache
@ -217,7 +287,8 @@ export class Relayer {
chainId: this._chainId!,
serviceFeePercent: this._serviceFee!,
miningFeePercent: this._miningFee!,
status: this._status!
status: this._status!,
prices: this._prices!
})
await cache.db.put(doc).catch((err) => {

View File

@ -14,16 +14,16 @@
"1cdai5000000": "0xD21be7248e0197Ee08E0c20D4a96DEBdaC3D20Af",
"1usdc100": "0xd96f2B1c14Db8458374d9Aca76E26c3D18364307",
"1usdc1000": "0x4736dCf1b7A3d580672CcE6E7c65cd5cc9cFBa9D",
"1usdc10000": "",
"1usdc100000": "",
"1usdc10000": null,
"1usdc100000": null,
"1usdt100": "0x169AD27A470D064DEDE56a2D3ff727986b15D52B",
"1usdt1000": "0x0836222F2B2B24A3F36f98668Ed8F0B38D1a872f",
"1usdt10000": "",
"1usdt100000": "",
"1usdt10000": null,
"1usdt100000": null,
"1wbtc0.1": "0x178169B423a011fff22B9e3F3abeA13414dDD0F1",
"1wbtc1": "0x610B717796ad172B316836AC95a2ffad065CeaB4",
"1wbtc10": "0xbB93e510BbCD0B7beb5A853875f9eC60275CF498",
"1wbtc100": "",
"1wbtc100": null,
"5eth0.1": "0x6Bf694a291DF3FeC1f7e69701E3ab6c592435Ae7",
"5eth1": "0x3aac1cC67c2ec5Db4eA850957b967Ba153aD6279",
"5eth10": "0x723B78e67497E85279CB204544566F4dC5d2acA0",
@ -38,16 +38,32 @@
"5cdai5000000": "0x57b2B8c82F065de8Ef5573f9730fC1449B403C9f",
"5usdc100": "0x05E0b5B40B7b66098C2161A5EE11C5740A3A7C45",
"5usdc1000": "0x23173fE8b96A4Ad8d2E17fB83EA5dcccdCa1Ae52",
"5usdc10000": "",
"5usdc100000": "",
"5usdc10000": null,
"5usdc100000": null,
"5usdt100": "0x538Ab61E8A9fc1b2f93b3dd9011d662d89bE6FE6",
"5usdt1000": "0x94Be88213a387E992Dd87DE56950a9aef34b9448",
"5usdt10000": "",
"5usdt100000": "",
"5usdt10000": null,
"5usdt100000": null,
"5wbtc0.1": "0x242654336ca2205714071898f67E254EB49ACdCe",
"5wbtc1": "0x776198CCF446DFa168347089d7338879273172cF",
"5wbtc10": "0xeDC5d01286f99A066559F60a585406f3878a033e",
"5wbtc100": ""
"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,
@ -64,15 +80,63 @@
"1cdai5000000": 12066053,
"1usdc100": 9161958,
"1usdc1000": 9161965,
"1usdc10000": "",
"1usdc100000": "",
"1usdc10000": null,
"1usdc100000": null,
"1usdt100": 9162005,
"1usdt1000": 9162012,
"1usdt10000": "",
"1usdt100000": "",
"1usdt10000": null,
"1usdt100000": null,
"1wbtc0.1": 12067529,
"1wbtc1": 12066652,
"1wbtc10": 12067591,
"1wbtc100": ""
"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"
}
}

View File

@ -5,19 +5,26 @@ import { solidity } from 'ethereum-waffle'
import { providers } from 'ethers'
import { parseUnits } from 'ethers/lib/utils'
import { ERC20 } from 'types/deth'
import { ERC20, TornadoInstance } from 'types/deth'
import { Json } from 'types/sdk/data'
import { Core } from 'lib/main'
import { Core } from 'lib/core'
import { Chain, Contracts } from 'lib/chain'
import { Files, OnchainData } from 'lib/data'
import { Docs, Files, OnchainData, Cache } from 'lib/data'
import { ErrorUtils } from 'lib/utils'
import { TorProvider } from 'lib/web'
// Data
// @ts-expect-error
import { parseIndexableString } from 'pouchdb-collate'
import compareDeposits from './resources/deposits_eth_0.1.json'
import { Primitives } from 'lib/crypto'
import { ZKDepositData } from 'types/sdk/crypto'
chai.use(solidity)
const expect = chai.expect
describe('main', () => {
describe.only('main', () => {
const torify = process.env.TORIFY === 'true'
if (!process.env.ETH_MAINNET_TEST_RPC) throw ErrorUtils.getError('need a mainnet rpc endpoint.')
@ -34,9 +41,7 @@ describe('main', () => {
? new TorProvider(process.env.ETH_MAINNET_TEST_RPC, { port: +process.env.TOR_PORT! })
: new providers.JsonRpcProvider(process.env.ETH_MAINNET_TEST_RPC)
const ganacheProvider = new providers.Web3Provider(
// @ts-ignore
ganache.provider({
const _ganacheProvider = ganache.provider({
chain: { chainId: 1 },
// @ts-ignore
fork: { url: process.env.ETH_MAINNET_TEST_RPC },
@ -46,7 +51,9 @@ describe('main', () => {
unlockedAccounts: [daiWhale]
}
})
)
// @ts-expect-error
const ganacheProvider = new providers.Web3Provider(_ganacheProvider)
const chain = new Chain(ganacheProvider)
let snapshotId: any
@ -57,7 +64,7 @@ describe('main', () => {
})
describe('namespace Tornado', () => {
describe('namespace Contracts', () => {
describe.skip('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')
@ -66,17 +73,17 @@ describe('main', () => {
})
describe('class Classic', () => {
it('sync: should be able to fetch a couple events', async () => {
it.skip('sync: Should be able to fetch deposit events', async () => {
const core = new Core(mainnetProvider)
const instance = await Contracts.getInstance(String(1), 'eth', String(0.1), mainnetProvider)
const targetBlock = 16928712
const startBlock = targetBlock - 7200
//const targetBlock = 16928712
//const startBlock = targetBlock - 7200
await core.sync(instance, {
//deposit: true,
//withdrawal: false,
blocks: {
startBlock: startBlock,
targetBlock: targetBlock
//startBlock: startBlock,
//targetBlock: targetBlock
},
cache: {
sync: {
@ -84,6 +91,21 @@ describe('main', () => {
}
}
})
const cache = core.caches.get('Deposits1ETH0.1')
const rows = (await cache!.db.allDocs()).rows
const valid = Object.values(compareDeposits)
expect(rows.length).to.be.gte(valid.length)
for (let i = 0, len = valid.length; i < len; i++) {
const id = rows[i].id
const [bn, leafIndex, commitment] = parseIndexableString(id)
const validDoc = valid[i]
expect(bn).to.equal(validDoc['blockNumber'])
expect(leafIndex).to.equal(validDoc['leafIndex'])
expect(commitment).to.equal(validDoc['commitment'])
}
}).timeout(0)
describe('ganache fork', async () => {
@ -93,6 +115,8 @@ describe('main', () => {
let needsMoneyAddress: string
let dai: ERC20
let smallestEth: TornadoInstance
let note: ZKDepositData, noteObj: any
before(async function () {
this.timeout(0)
@ -102,6 +126,7 @@ describe('main', () => {
needsMoneyAddress = await needsMoney.getAddress()
daiData = await OnchainData.getTokenData('1', 'dai')
dai = chain.getTokenContract(daiData.address).connect(whale)
smallestEth = await core.getInstance('eth', 0.1)
})
after(async function () {
this.timeout(0)
@ -112,20 +137,72 @@ describe('main', () => {
dai = dai.connect(whale)
})
it('buildDepositTx: build a single eth deposit tx and succeed', async () => {
it.only('buildDepositTx: build a single eth deposit tx and succeed', async () => {
const signer = ganacheProvider.getSigner()
const initBal = await signer.getBalance()
const tx = await core.buildDepositTx(await core.getInstance('eth', 100))
await signer.sendTransaction(tx.request)
const tx = await core.buildDepositTx(smallestEth)
const response = await signer.sendTransaction(tx.request)
const receipt = await response.wait()
noteObj = {
blockNumber: receipt.blockNumber,
transactionHash: receipt.transactionHash,
args: {
commitment: '',
leafIndex: 0,
timestamp: response.timestamp
}
}
console.log(receipt, '\n')
note = Primitives.parseNote(tx.note!)
const endBal = await signer.getBalance()
expect(initBal).to.equal(parseUnits('1000'))
expect(endBal).to.be.lte(parseUnits('900'))
expect(endBal).to.be.lte(parseUnits('999.9'))
}).timeout(0)
it('buildDepositTx: build a single token deposit tx and succeed', async () => {
it.only('buildDepositProofs: it should be able to build', async () => {
try {
const instance = await core.getInstance('eth', 0.1)
const signer = ganacheProvider.getSigner()
const withdrawer = ganacheProvider.getSigner(2)
const cache = core.loadCache('Deposits1ETH0.1') as Cache.Base<Docs.Deposit>
noteObj['args'] = {
commitment: note.hexCommitment,
leafIndex: (await cache!.db.allDocs({ descending: true, limit: 1, include_docs: true }))
?.rows[0].doc?.leafIndex,
timestamp: noteObj['args']['timestamp']
}
console.log(noteObj, '\n')
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
)
console.log(proof)
} catch (err) {
console.log(ErrorUtils.ensureError(err).message)
throw err
}
}).timeout(0)
it.skip('buildDepositTx: 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')
@ -142,7 +219,7 @@ describe('main', () => {
expect(await dai.balanceOf(needsMoneyAddress)).to.equal(0)
}).timeout(0)
it('buildDepositTxs: multiple eth deposits', async () => {
it.skip('buildDepositTxs: multiple eth deposits', async () => {
const instances = await core.getInstances(
[0.1, 1, 10, 100].map((el) => {
return { token: 'eth', denomination: el }
@ -159,7 +236,7 @@ describe('main', () => {
expect(await dai.balanceOf(needsMoneyAddress)).to.equal(0)
}).timeout(0)
it('buildDepositTxs: multiple token deposits', async () => {
it.skip('buildDepositTxs: multiple token deposits', async () => {
const instances = await core.getInstances(
[100, 1000, 10000, 100000].map((el) => {
return { token: 'dai', denomination: el }
@ -185,7 +262,7 @@ describe('main', () => {
expect(await dai.balanceOf(needsMoneyAddress)).to.equal(0)
}).timeout(0)
it('createInvoice: should be able to create an invoice', async () => {
it.skip('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)

File diff suppressed because it is too large Load Diff

View File

@ -18,6 +18,7 @@ describe('web', () => {
const torProvider = new TorProvider(process.env.ETH_MAINNET_TEST_RPC, { port: +process.env.TOR_PORT })
const httpClient = new TorHttpClient({ port: +process.env.TOR_PORT })
if (process.env.TORIFY === 'true')
console.log(
'\nSome Tor tips: Support non-profit exit node operators, host your own nodes, avoid spy nodes by configuring torrc.\n'
)
@ -41,7 +42,7 @@ describe('web', () => {
}
}).timeout(0)
it.only('TorProvider: Should be able to fetch some basic blockchain data over Tor', async () => {
it('TorProvider: Should be able to fetch some basic blockchain data over Tor', async () => {
try {
console.log('\nBlock Number: ' + (await torProvider.getBlockNumber()))
console.log('Gas Price: ' + (await torProvider.getGasPrice()).div(1000000000) + ' gwei')
@ -55,7 +56,7 @@ describe('web', () => {
}
}).timeout(0)
it.skip('DISCONNECTED: Should not be able to request over Tor', async function () {
it('DISCONNECTED: Should not be able to request over Tor', async function () {
try {
await torProvider.getBlockNumber()
throw ErrorUtils.getError('should not have succeeded.')

View File

@ -7,7 +7,6 @@
import { TransactionRequest } from '@ethersproject/abstract-provider'
import { BigNumber } from 'ethers'
import { RelayerProperties as RelayerDataProperties } from 'types/sdk/data'
export namespace Options {
export namespace Cache {
@ -48,9 +47,13 @@ export namespace Options {
export type Invoice = Deposit
export interface BuildDepositProof {
gasPrice?: BigNumber
gasPriceCushion?: BigNumber
tokenDecimals?: number
ethPurchaseAmounts?: Array<BigNumber>
merkleTreeHeight?: number
checkNotesSpent?: boolean
checkKnownRoot?: boolean
merkleTreeHeight?: number
}
}
}

View File

@ -34,9 +34,9 @@ export namespace OutputOf {
}
export interface Groth16Proof {
pi_a: Array<string>
pi_b: Array<string>
pi_c: Array<string>
pi_a: string
pi_b: string
pi_c: string
}
}
@ -50,6 +50,7 @@ type __OutputAliasDelimiter = null
export type MerkleProof = OutputOf.MerkleProof
export type ZKProof = OutputOf.Groth16Proof
export type DepositProof = OutputOf.Groth16Proof
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INPUTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
@ -82,8 +83,8 @@ export namespace InputFor {
hexNullifierHash: string
recipientAddress: string
relayerAddress: string
fee: number
refund: number
fee: bigInt
refund: bigInt
}
private: {
nullifier: bigInt
@ -104,7 +105,7 @@ export namespace InputFor {
nullifier: bigInt
secret: bigInt
pathIndices: number[]
pathElements: any[]
pathElements: string[]
}
export type Groth16 = PublicGroth16 & PrivateGroth16

View File

@ -1,49 +1,4 @@
import { isAddress } from 'ethers/lib/utils'
import { ErrorUtils } from 'lib/utils'
// TODO: Decide whether to really use below, possibly from external interface
type NetworkId = string | number
type TokenId = string
type ContractId = string
type Denomination = number
class DataKey<T extends TokenId | NetworkId | ContractId | Denomination> {
value: string
isAddress?: boolean
isSymbol?: boolean
isName?: boolean
constructor(id: T) {
this.value = this._validate(id)
}
private _validate(id: T): string {
let type = typeof id
switch (type) {
case 'string':
let val = id as string
if (isAddress(val)) {
this.isAddress = true
return val
} else {
this.isSymbol = true
this.isName = true
}
return val.toLowerCase()
case 'number':
return String(id)
default:
throw ErrorUtils.getError(`unsupported key type ${type}.`)
}
}
}
type NetworkKey = DataKey<NetworkId>
type TokenKey = DataKey<TokenId>
type ContractKey = DataKey<ContractId>
type DenominationKey = DataKey<Denomination>
import { BigNumber } from 'ethers'
export namespace Json {
export interface TornadoInstance {
@ -81,4 +36,5 @@ export interface RelayerProperties {
miningFeePercent: number
status: string
chainId: number
prices: Map<string, BigNumber>
}

View File

@ -1,7 +1,16 @@
import { AxiosInstance } from 'axios'
export interface RelayerOptions {
export namespace Relayer {
export interface Options {
url: string
address?: string
httpClient: AxiosInstance
}
export interface WithdrawalRequestResult {
success: boolean
txHash?: string
}
}
export type RelayerOptions = Relayer.Options

View File

@ -6,20 +6,23 @@
"require": ["tsconfig-paths/register"]
},
"compilerOptions": {
"target": "es2017",
// ~~~~~~~~~~~~~~~~~~~~~~~~~NODE 18 STANDARD~~~~~~~~~~~~~~~~~~~~~~~
"target": "es2022",
"module": "commonjs",
"lib": ["es2020"],
"lib": ["es2022"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"moduleResolution": "node",
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"outDir": "./build",
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"strict": true,
"checkJs": true,
"allowJs": true,
"skipLibCheck": true,
"baseUrl": ".",
"paths": {
"test/*": ["src/test/*"],

364
yarn.lock
View File

@ -30,14 +30,26 @@
dependencies:
"@jridgewell/trace-mapping" "0.3.9"
"@eslint/eslintrc@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.0.tgz#943309d8697c52fc82c076e90c1c74fbbe69dbff"
integrity sha512-fluIaaV+GyV24CCu/ggiHdV+j4RNh85yQnAYS/G2mZODZgGmmlrgCydjUcV3YvxCm9x8nMAfThsqTni4KiXT4A==
"@eslint-community/eslint-utils@^4.2.0":
version "4.4.0"
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==
dependencies:
eslint-visitor-keys "^3.3.0"
"@eslint-community/regexpp@^4.4.0":
version "4.5.0"
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.0.tgz#f6f729b02feee2c749f57e334b7a1b5f40a81724"
integrity sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==
"@eslint/eslintrc@^2.0.2":
version "2.0.2"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.2.tgz#01575e38707add677cf73ca1589abba8da899a02"
integrity sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==
dependencies:
ajv "^6.12.4"
debug "^4.3.2"
espree "^9.4.0"
espree "^9.5.1"
globals "^13.19.0"
ignore "^5.2.0"
import-fresh "^3.2.1"
@ -45,10 +57,10 @@
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
"@eslint/js@8.35.0":
version "8.35.0"
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.35.0.tgz#b7569632b0b788a0ca0e438235154e45d42813a7"
integrity sha512-JXdzbRiWclLVoD8sNUjR443VVlYqiYmDVT6rGUEIEHU5YJW0gaVZwV2xgM7D4arkvASqD0IlLUVjHiFuxaftRw==
"@eslint/js@8.38.0":
version "8.38.0"
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.38.0.tgz#73a8a0d8aa8a8e6fe270431c5e72ae91b5337892"
integrity sha512-IoD2MfUnOV58ghIHCiil01PcohxjbYR/qCxsoC+xNgUwh1EY8jOOrYmu3d3a71+tJJ23uscEV4X2HJWMsPJu4g==
"@ethereum-waffle/chai@4.0.10":
version "4.0.10"
@ -622,14 +634,14 @@
integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==
"@jridgewell/resolve-uri@^3.0.3":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
version "3.1.1"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721"
integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==
"@jridgewell/sourcemap-codec@^1.4.10":
version "1.4.14"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
version "1.4.15"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
"@jridgewell/trace-mapping@0.3.9":
version "0.3.9"
@ -738,6 +750,16 @@
dependencies:
node-gyp-build "4.3.0"
"@trufflesuite/uws-js-unofficial@20.10.0-unofficial.2":
version "20.10.0-unofficial.2"
resolved "https://registry.yarnpkg.com/@trufflesuite/uws-js-unofficial/-/uws-js-unofficial-20.10.0-unofficial.2.tgz#7ed613ce3260cd5d1773a4d5787a2a106acd1a91"
integrity sha512-oQQlnS3oNeGsgS4K3KCSSavJgSb0W9D5ktZs4FacX9VbM7b+NlhjH96d6/G4fMrz+bc5MXRyco419on0X0dvRA==
dependencies:
ws "8.2.3"
optionalDependencies:
bufferutil "4.0.5"
utf-8-validate "5.0.7"
"@tsconfig/node10@^1.0.7":
version "1.0.9"
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
@ -888,14 +910,14 @@
integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==
"@types/node-fetch@^2.6.1":
version "2.6.2"
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.2.tgz#d1a9c5fd049d9415dce61571557104dec3ec81da"
integrity sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==
version "2.6.3"
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.3.tgz#175d977f5e24d93ad0f57602693c435c57ad7e80"
integrity sha512-ETTL1mOEdq/sxUtgtOhKjyB2Irra4cjxksvcMUR5Zr4n+PxVhsCD9WS46oPbHL3et9Zde7CNRr+WUNlcHvsX+w==
dependencies:
"@types/node" "*"
form-data "^3.0.0"
"@types/node@*":
"@types/node@*", "@types/node@^18.15.0":
version "18.15.11"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.11.tgz#b3b790f09cb1696cffcec605de025b088fa4225f"
integrity sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==
@ -910,11 +932,6 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240"
integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==
"@types/node@^18.15.0":
version "18.15.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.0.tgz#286a65e3fdffd691e170541e6ecb0410b16a38be"
integrity sha512-z6nr0TTEOBGkzLGmbypWOGnpSpSIBorEhC4L+4HeQ2iezKCi4f77kyslRwvHeNitymGQ+oFyIWGP96l/DPSV9w==
"@types/normalize-package-data@^2.4.0":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301"
@ -1103,87 +1120,87 @@
integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==
"@typescript-eslint/eslint-plugin@^5.54.1":
version "5.54.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.54.1.tgz#0c5091289ce28372e38ab8d28e861d2dbe1ab29e"
integrity sha512-a2RQAkosH3d3ZIV08s3DcL/mcGc2M/UC528VkPULFxR9VnVPT8pBu0IyBAJJmVsCmhVfwQX1v6q+QGnmSe1bew==
version "5.58.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.58.0.tgz#b1d4b0ad20243269d020ef9bbb036a40b0849829"
integrity sha512-vxHvLhH0qgBd3/tW6/VccptSfc8FxPQIkmNTVLWcCOVqSBvqpnKkBTYrhcGlXfSnd78azwe+PsjYFj0X34/njA==
dependencies:
"@typescript-eslint/scope-manager" "5.54.1"
"@typescript-eslint/type-utils" "5.54.1"
"@typescript-eslint/utils" "5.54.1"
"@eslint-community/regexpp" "^4.4.0"
"@typescript-eslint/scope-manager" "5.58.0"
"@typescript-eslint/type-utils" "5.58.0"
"@typescript-eslint/utils" "5.58.0"
debug "^4.3.4"
grapheme-splitter "^1.0.4"
ignore "^5.2.0"
natural-compare-lite "^1.4.0"
regexpp "^3.2.0"
semver "^7.3.7"
tsutils "^3.21.0"
"@typescript-eslint/parser@^5.54.1":
version "5.54.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.54.1.tgz#05761d7f777ef1c37c971d3af6631715099b084c"
integrity sha512-8zaIXJp/nG9Ff9vQNh7TI+C3nA6q6iIsGJ4B4L6MhZ7mHnTMR4YP5vp2xydmFXIy8rpyIVbNAG44871LMt6ujg==
version "5.58.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.58.0.tgz#2ac4464cf48bef2e3234cb178ede5af352dddbc6"
integrity sha512-ixaM3gRtlfrKzP8N6lRhBbjTow1t6ztfBvQNGuRM8qH1bjFFXIJ35XY+FC0RRBKn3C6cT+7VW1y8tNm7DwPHDQ==
dependencies:
"@typescript-eslint/scope-manager" "5.54.1"
"@typescript-eslint/types" "5.54.1"
"@typescript-eslint/typescript-estree" "5.54.1"
"@typescript-eslint/scope-manager" "5.58.0"
"@typescript-eslint/types" "5.58.0"
"@typescript-eslint/typescript-estree" "5.58.0"
debug "^4.3.4"
"@typescript-eslint/scope-manager@5.54.1":
version "5.54.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.54.1.tgz#6d864b4915741c608a58ce9912edf5a02bb58735"
integrity sha512-zWKuGliXxvuxyM71UA/EcPxaviw39dB2504LqAmFDjmkpO8qNLHcmzlh6pbHs1h/7YQ9bnsO8CCcYCSA8sykUg==
"@typescript-eslint/scope-manager@5.58.0":
version "5.58.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.58.0.tgz#5e023a48352afc6a87be6ce3c8e763bc9e2f0bc8"
integrity sha512-b+w8ypN5CFvrXWQb9Ow9T4/6LC2MikNf1viLkYTiTbkQl46CnR69w7lajz1icW0TBsYmlpg+mRzFJ4LEJ8X9NA==
dependencies:
"@typescript-eslint/types" "5.54.1"
"@typescript-eslint/visitor-keys" "5.54.1"
"@typescript-eslint/types" "5.58.0"
"@typescript-eslint/visitor-keys" "5.58.0"
"@typescript-eslint/type-utils@5.54.1":
version "5.54.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.54.1.tgz#4825918ec27e55da8bb99cd07ec2a8e5f50ab748"
integrity sha512-WREHsTz0GqVYLIbzIZYbmUUr95DKEKIXZNH57W3s+4bVnuF1TKe2jH8ZNH8rO1CeMY3U4j4UQeqPNkHMiGem3g==
"@typescript-eslint/type-utils@5.58.0":
version "5.58.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.58.0.tgz#f7d5b3971483d4015a470d8a9e5b8a7d10066e52"
integrity sha512-FF5vP/SKAFJ+LmR9PENql7fQVVgGDOS+dq3j+cKl9iW/9VuZC/8CFmzIP0DLKXfWKpRHawJiG70rVH+xZZbp8w==
dependencies:
"@typescript-eslint/typescript-estree" "5.54.1"
"@typescript-eslint/utils" "5.54.1"
"@typescript-eslint/typescript-estree" "5.58.0"
"@typescript-eslint/utils" "5.58.0"
debug "^4.3.4"
tsutils "^3.21.0"
"@typescript-eslint/types@5.54.1":
version "5.54.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.54.1.tgz#29fbac29a716d0f08c62fe5de70c9b6735de215c"
integrity sha512-G9+1vVazrfAfbtmCapJX8jRo2E4MDXxgm/IMOF4oGh3kq7XuK3JRkOg6y2Qu1VsTRmWETyTkWt1wxy7X7/yLkw==
"@typescript-eslint/types@5.58.0":
version "5.58.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.58.0.tgz#54c490b8522c18986004df7674c644ffe2ed77d8"
integrity sha512-JYV4eITHPzVQMnHZcYJXl2ZloC7thuUHrcUmxtzvItyKPvQ50kb9QXBkgNAt90OYMqwaodQh2kHutWZl1fc+1g==
"@typescript-eslint/typescript-estree@5.54.1":
version "5.54.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.54.1.tgz#df7b6ae05fd8fef724a87afa7e2f57fa4a599be1"
integrity sha512-bjK5t+S6ffHnVwA0qRPTZrxKSaFYocwFIkZx5k7pvWfsB1I57pO/0M0Skatzzw1sCkjJ83AfGTL0oFIFiDX3bg==
"@typescript-eslint/typescript-estree@5.58.0":
version "5.58.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.58.0.tgz#4966e6ff57eaf6e0fce2586497edc097e2ab3e61"
integrity sha512-cRACvGTodA+UxnYM2uwA2KCwRL7VAzo45syNysqlMyNyjw0Z35Icc9ihPJZjIYuA5bXJYiJ2YGUB59BqlOZT1Q==
dependencies:
"@typescript-eslint/types" "5.54.1"
"@typescript-eslint/visitor-keys" "5.54.1"
"@typescript-eslint/types" "5.58.0"
"@typescript-eslint/visitor-keys" "5.58.0"
debug "^4.3.4"
globby "^11.1.0"
is-glob "^4.0.3"
semver "^7.3.7"
tsutils "^3.21.0"
"@typescript-eslint/utils@5.54.1":
version "5.54.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.54.1.tgz#7a3ee47409285387b9d4609ea7e1020d1797ec34"
integrity sha512-IY5dyQM8XD1zfDe5X8jegX6r2EVU5o/WJnLu/znLPWCBF7KNGC+adacXnt5jEYS9JixDcoccI6CvE4RCjHMzCQ==
"@typescript-eslint/utils@5.58.0":
version "5.58.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.58.0.tgz#430d7c95f23ec457b05be5520c1700a0dfd559d5"
integrity sha512-gAmLOTFXMXOC+zP1fsqm3VceKSBQJNzV385Ok3+yzlavNHZoedajjS4UyS21gabJYcobuigQPs/z71A9MdJFqQ==
dependencies:
"@eslint-community/eslint-utils" "^4.2.0"
"@types/json-schema" "^7.0.9"
"@types/semver" "^7.3.12"
"@typescript-eslint/scope-manager" "5.54.1"
"@typescript-eslint/types" "5.54.1"
"@typescript-eslint/typescript-estree" "5.54.1"
"@typescript-eslint/scope-manager" "5.58.0"
"@typescript-eslint/types" "5.58.0"
"@typescript-eslint/typescript-estree" "5.58.0"
eslint-scope "^5.1.1"
eslint-utils "^3.0.0"
semver "^7.3.7"
"@typescript-eslint/visitor-keys@5.54.1":
version "5.54.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.54.1.tgz#d7a8a0f7181d6ac748f4d47b2306e0513b98bf8b"
integrity sha512-q8iSoHTgwCfgcRJ2l2x+xCbu8nBlRAlsQ33k24Adj8eoVBE0f8dUeI+bAa8F84Mv05UGbAx57g2zrRsYIooqQg==
"@typescript-eslint/visitor-keys@5.58.0":
version "5.58.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.58.0.tgz#eb9de3a61d2331829e6761ce7fd13061781168b4"
integrity sha512-/fBraTlPj0jwdyTwLyrRTxv/3lnU2H96pNTVM6z3esTWLtA5MZ9ghSMJ7Rb+TtUAdtEw9EyJzJ0EydIMKxQ9gA==
dependencies:
"@typescript-eslint/types" "5.54.1"
"@typescript-eslint/types" "5.58.0"
eslint-visitor-keys "^3.3.0"
"@uniswap/default-token-list@^9.3.0":
@ -2241,9 +2258,9 @@ cookiejar@^2.1.1:
integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==
core-js-pure@^3.0.1:
version "3.29.1"
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.29.1.tgz#1be6ca2b8772f6b4df7fc4621743286e676c6162"
integrity sha512-4En6zYVi0i0XlXHVz/bi6l1XDjCqkKRq765NXuX+SnaIatlE96Odt5lMLjdxUiNI1v9OXI5DSLWYPlmTfkTktg==
version "3.30.1"
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.30.1.tgz#7d93dc89e7d47b8ef05d7e79f507b0e99ea77eec"
integrity sha512-nXBEVpmUnNRhz83cHd9JRQC52cTMcuXAmR56+9dSMpRdpeA4I1PX6yjmhd71Eyc/wXNsdBdUDIj1QTIeZpU5Tg==
core-util-is@1.0.2:
version "1.0.2"
@ -2656,9 +2673,9 @@ eslint-scope@^5.1.1:
estraverse "^4.1.1"
eslint-scope@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642"
integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==
version "7.2.0"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.0.tgz#f21ebdafda02352f103634b96dd47d9f81ca117b"
integrity sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==
dependencies:
esrecurse "^4.3.0"
estraverse "^5.2.0"
@ -2670,27 +2687,15 @@ eslint-utils@^1.3.1:
dependencies:
eslint-visitor-keys "^1.1.0"
eslint-utils@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672"
integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==
dependencies:
eslint-visitor-keys "^2.0.0"
eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e"
integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==
eslint-visitor-keys@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
eslint-visitor-keys@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz#c7f0f956124ce677047ddbc192a68f999454dedc"
integrity sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==
eslint@^5.16.0:
version "5.16.0"
@ -2735,12 +2740,14 @@ eslint@^5.16.0:
text-table "^0.2.0"
eslint@^8.35.0:
version "8.35.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.35.0.tgz#fffad7c7e326bae606f0e8f436a6158566d42323"
integrity sha512-BxAf1fVL7w+JLRQhWl2pzGeSiGqbWumV4WNvc9Rhp6tiCtm4oHnyPBSEtMGZwrQgudFQ+otqzWoPB7x+hxoWsw==
version "8.38.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.38.0.tgz#a62c6f36e548a5574dd35728ac3c6209bd1e2f1a"
integrity sha512-pIdsD2jwlUGf/U38Jv97t8lq6HpaU/G9NKbYmpWpZGw3LdTNhZLbJePqxOXGB5+JEKfOPU/XLxYxFh03nr1KTg==
dependencies:
"@eslint/eslintrc" "^2.0.0"
"@eslint/js" "8.35.0"
"@eslint-community/eslint-utils" "^4.2.0"
"@eslint-community/regexpp" "^4.4.0"
"@eslint/eslintrc" "^2.0.2"
"@eslint/js" "8.38.0"
"@humanwhocodes/config-array" "^0.11.8"
"@humanwhocodes/module-importer" "^1.0.1"
"@nodelib/fs.walk" "^1.2.8"
@ -2751,9 +2758,8 @@ eslint@^8.35.0:
doctrine "^3.0.0"
escape-string-regexp "^4.0.0"
eslint-scope "^7.1.1"
eslint-utils "^3.0.0"
eslint-visitor-keys "^3.3.0"
espree "^9.4.0"
eslint-visitor-keys "^3.4.0"
espree "^9.5.1"
esquery "^1.4.2"
esutils "^2.0.2"
fast-deep-equal "^3.1.3"
@ -2775,7 +2781,6 @@ eslint@^8.35.0:
minimatch "^3.1.2"
natural-compare "^1.4.0"
optionator "^0.9.1"
regexpp "^3.2.0"
strip-ansi "^6.0.1"
strip-json-comments "^3.1.0"
text-table "^0.2.0"
@ -2789,14 +2794,14 @@ espree@^5.0.1:
acorn-jsx "^5.0.0"
eslint-visitor-keys "^1.0.0"
espree@^9.4.0:
version "9.4.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.1.tgz#51d6092615567a2c2cff7833445e37c28c0065bd"
integrity sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==
espree@^9.5.1:
version "9.5.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.1.tgz#4f26a4d5f18905bf4f2e0bd99002aab807e96dd4"
integrity sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==
dependencies:
acorn "^8.8.0"
acorn-jsx "^5.3.2"
eslint-visitor-keys "^3.3.0"
eslint-visitor-keys "^3.4.0"
esprima@^4.0.0:
version "4.0.1"
@ -3328,9 +3333,9 @@ fresh@0.5.2:
integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==
fs-extra@^11.1.0:
version "11.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.0.tgz#5784b102104433bb0e090f48bfc4a30742c357ed"
integrity sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==
version "11.1.1"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.1.tgz#da69f7c39f3b002378b0954bb6ae7efdc0876e2d"
integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==
dependencies:
graceful-fs "^4.2.0"
jsonfile "^6.0.1"
@ -3399,11 +3404,12 @@ ganache@7.4.3:
utf-8-validate "5.0.7"
ganache@^7.7.7:
version "7.7.7"
resolved "https://registry.yarnpkg.com/ganache/-/ganache-7.7.7.tgz#19939a86799f0bcb7df02e88082944466394b913"
integrity sha512-kZUuOcgDQBtbxzs4iB3chg1iAc28s2ffdOdzyTTzo4vr9sb843w4PbWd5v1hsIqtcNjurcpLaW8XRp/cw2u++g==
version "7.8.0"
resolved "https://registry.yarnpkg.com/ganache/-/ganache-7.8.0.tgz#02154384f246b66e98974cbcbb18e8372df3c2e0"
integrity sha512-IrUYvsaE/m2/NaVIZ7D/gCnsmyU/buechnH6MhUipzG1qJcZIwIp/DoP/LZUcHyhy0Bv0NKZD2pGOjpRhn7l7A==
dependencies:
"@trufflesuite/bigint-buffer" "1.1.10"
"@trufflesuite/uws-js-unofficial" "20.10.0-unofficial.2"
"@types/bn.js" "^5.1.0"
"@types/lru-cache" "5.1.1"
"@types/seedrandom" "3.0.1"
@ -3563,12 +3569,12 @@ glob@^7.1.2, glob@^7.1.3:
path-is-absolute "^1.0.0"
glob@^9.2.0:
version "9.2.1"
resolved "https://registry.yarnpkg.com/glob/-/glob-9.2.1.tgz#f47e34e1119e7d4f93a546e75851ba1f1e68de50"
integrity sha512-Pxxgq3W0HyA3XUvSXcFhRSs+43Jsx0ddxcFrbjxNGkL2Ak5BAUBxLqI5G6ADDeCHLfzzXFhe0b1yYcctGmytMA==
version "9.3.5"
resolved "https://registry.yarnpkg.com/glob/-/glob-9.3.5.tgz#ca2ed8ca452781a3009685607fdf025a899dfe21"
integrity sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==
dependencies:
fs.realpath "^1.0.0"
minimatch "^7.4.1"
minimatch "^8.0.2"
minipass "^4.2.4"
path-scurry "^1.6.1"
@ -3647,16 +3653,11 @@ got@^11.8.5:
p-cancelable "^2.0.0"
responselike "^2.0.0"
graceful-fs@^4.1.2, graceful-fs@^4.1.6:
graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0:
version "4.2.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
graceful-fs@^4.2.0:
version "4.2.10"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
grapheme-splitter@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
@ -3949,10 +3950,10 @@ is-callable@^1.1.3:
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055"
integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==
is-core-module@^2.5.0, is-core-module@^2.9.0:
version "2.11.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144"
integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==
is-core-module@^2.12.0, is-core-module@^2.5.0:
version "2.12.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.0.tgz#36ad62f6f73c8253fd6472517a12483cf03e7ec4"
integrity sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==
dependencies:
has "^1.0.3"
@ -4086,9 +4087,9 @@ isstream@~0.1.2:
integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==
js-sdsl@^4.1.4:
version "4.3.0"
resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.3.0.tgz#aeefe32a451f7af88425b11fdb5f58c90ae1d711"
integrity sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==
version "4.4.0"
resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.4.0.tgz#8b437dbe642daa95760400b602378ed8ffea8430"
integrity sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==
js-sha3@0.8.0, js-sha3@^0.8.0:
version "0.8.0"
@ -4518,10 +4519,10 @@ lru-cache@^6.0.0:
dependencies:
yallist "^4.0.0"
lru-cache@^7.14.1:
version "7.18.3"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89"
integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==
lru-cache@^9.0.0:
version "9.0.3"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-9.0.3.tgz#8a04f282df5320227bb7215c55df2660d3e4e25b"
integrity sha512-cyjNRew29d4kbgnz1sjDqxg7qg8NW4s+HQzCGjeon7DV5T2yDije16W9HaUFV1dhVEMh+SjrOcK0TomBmf3Egg==
ltgt@2.2.1, ltgt@^2.1.2, ltgt@~2.2.0:
version "2.2.1"
@ -4740,10 +4741,10 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
dependencies:
brace-expansion "^1.1.7"
minimatch@^7.4.1:
version "7.4.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-7.4.2.tgz#157e847d79ca671054253b840656720cb733f10f"
integrity sha512-xy4q7wou3vUoC9k1xGTXc+awNdGaGVHtFUaey8tiX4H1QRc04DZ/rmDFwNm2EBsuYEhAZ6SgMmYf3InGY6OauA==
minimatch@^8.0.2:
version "8.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-8.0.4.tgz#847c1b25c014d4e9a7f68aaf63dedd668a626229"
integrity sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==
dependencies:
brace-expansion "^2.0.1"
@ -4769,10 +4770,15 @@ minipass@^2.6.0, minipass@^2.9.0:
safe-buffer "^5.1.2"
yallist "^3.0.0"
minipass@^4.0.2, minipass@^4.2.4:
version "4.2.4"
resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.4.tgz#7d0d97434b6a19f59c5c3221698b48bbf3b2cd06"
integrity sha512-lwycX3cBMTvcejsHITUgYj6Gy6A7Nh4Q6h9NP4sTHY1ccJlC7yKzDmiShEHsJ16Jf1nKGDEaiHxiltsJEvk0nQ==
minipass@^4.2.4:
version "4.2.8"
resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.8.tgz#f0010f64393ecfc1d1ccb5f582bcaf45f48e1a3a"
integrity sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==
minipass@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d"
integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==
minizlib@^1.3.3:
version "1.3.3"
@ -5297,12 +5303,12 @@ path-parse@^1.0.7:
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
path-scurry@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.6.1.tgz#dab45f7bb1d3f45a0e271ab258999f4ab7e23132"
integrity sha512-OW+5s+7cw6253Q4E+8qQ/u1fVvcJQCJo/VFD8pje+dbJCF1n5ZRMV2AEHbGp+5Q7jxQIYJxkHopnj6nzdGeZLA==
version "1.7.0"
resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.7.0.tgz#99c741a2cfbce782294a39994d63748b5a24f6db"
integrity sha512-UkZUeDjczjYRE495+9thsgcVgsaCPkaw80slmfVFgllxY+IO8ubTsOpFVjDPROBqJdHfVPUFRHPBV/WciOVfWg==
dependencies:
lru-cache "^7.14.1"
minipass "^4.0.2"
lru-cache "^9.0.0"
minipass "^5.0.0"
path-to-regexp@0.1.7:
version "0.1.7"
@ -5542,9 +5548,9 @@ prettier-linter-helpers@^1.0.0:
fast-diff "^1.1.2"
prettier@^2.3.0, prettier@^2.3.1:
version "2.8.4"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.4.tgz#34dd2595629bfbb79d344ac4a91ff948694463c3"
integrity sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==
version "2.8.7"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.7.tgz#bb79fc8729308549d28fe3a98fce73d2c0656450"
integrity sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==
process-nextick-args@~2.0.0:
version "2.0.1"
@ -5793,11 +5799,6 @@ regexpp@^2.0.1:
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f"
integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==
regexpp@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
request@^2.79.0, request@^2.85.0:
version "2.88.2"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
@ -5850,11 +5851,11 @@ resolve-from@^4.0.0:
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
resolve@^1.10.0:
version "1.22.1"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
version "1.22.3"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.3.tgz#4b4055349ffb962600972da1fdc33c46a4eb3283"
integrity sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==
dependencies:
is-core-module "^2.9.0"
is-core-module "^2.12.0"
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
@ -5893,9 +5894,9 @@ rimraf@^3.0.2:
glob "^7.1.3"
rimraf@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-4.4.0.tgz#c7a9f45bb2ec058d2e60ef9aca5167974313d605"
integrity sha512-X36S+qpCUR0HjXlkDe4NAOhS//aHH0Z+h8Ckf2auGJk3PTnx5rLmrHkwNdbVQuCSUhOyFrlRvFEllZOYE+yZGQ==
version "4.4.1"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-4.4.1.tgz#bd33364f67021c5b79e93d7f4fa0568c7c21b755"
integrity sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==
dependencies:
glob "^9.2.0"
@ -5995,9 +5996,9 @@ semver@^6.0.0:
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@^7.3.4, semver@^7.3.7:
version "7.3.8"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798"
integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==
version "7.4.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.4.0.tgz#8481c92feffc531ab1e012a8ffc15bdd3a0f4318"
integrity sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==
dependencies:
lru-cache "^6.0.0"
@ -6582,9 +6583,9 @@ trim-newlines@^3.0.0:
integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==
ts-command-line-args@^2.2.0:
version "2.4.2"
resolved "https://registry.yarnpkg.com/ts-command-line-args/-/ts-command-line-args-2.4.2.tgz#b4815b23c35f8a0159d4e69e01012d95690bc448"
integrity sha512-mJLQQBOdyD4XI/ZWQY44PIdYde47JhV2xl380O7twPkTQ+Y5vFDHsk8LOeXKuz7dVY5aDCfAzRarNfSqtKOkQQ==
version "2.5.0"
resolved "https://registry.yarnpkg.com/ts-command-line-args/-/ts-command-line-args-2.5.0.tgz#7eeed3a6937b2612ea08a0794cf9d43fbbea89c4"
integrity sha512-Ff7Xt04WWCjj/cmPO9eWTJX3qpBZWuPWyQYG1vnxJao+alWWYjwJBc5aYz3h5p5dE08A6AnpkgiCtP/0KXXBYw==
dependencies:
"@morgan-stanley/ts-mocking-bird" "^0.6.2"
chalk "^4.1.0"
@ -6622,9 +6623,9 @@ ts-node@^10.9.1:
yn "3.1.1"
tsc-alias@^1.2.11:
version "1.8.3"
resolved "https://registry.yarnpkg.com/tsc-alias/-/tsc-alias-1.8.3.tgz#fe0c8331edd69b94160b2b936752b114f8063cb5"
integrity sha512-/9JARcmXBrEqSuLjdSOqxY7/xI/AnvmBi4CU9/Ba2oX6Oq8vnd0OGSQTk+PIwqWJ5ZxskV0X/x15yzxCNTHU+g==
version "1.8.5"
resolved "https://registry.yarnpkg.com/tsc-alias/-/tsc-alias-1.8.5.tgz#6b74e938230573354c9118deb58fd341d06d6253"
integrity sha512-Y3ka0olwSRdbHPyX5kXhYY2aoBKuT53DFdeY+PpQUR4hg5M/b8eIRmC8dL4FBdd0wT366iWc6iDUUGe6QwI7mg==
dependencies:
chokidar "^3.5.3"
commander "^9.0.0"
@ -6634,9 +6635,9 @@ tsc-alias@^1.2.11:
plimit-lit "^1.2.6"
tsconfig-paths@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.1.2.tgz#4819f861eef82e6da52fb4af1e8c930a39ed979a"
integrity sha512-uhxiMgnXQp1IR622dUXI+9Ehnws7i/y6xvpZB9IbUVOPy0muvdvgXeZOn88UcGPiT98Vp3rJPTa8bFoalZ3Qhw==
version "4.2.0"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz#ef78e19039133446d244beac0fd6a1632e2d107c"
integrity sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==
dependencies:
json5 "^2.2.2"
minimist "^1.2.6"
@ -6746,10 +6747,10 @@ typedarray-to-buffer@^3.1.5:
dependencies:
is-typedarray "^1.0.0"
typescript@^5.1.0-dev.20230310:
version "5.1.0-dev.20230316"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.0-dev.20230316.tgz#d57f1bde040419beaacf92ecb8adc5e29ecabdd5"
integrity sha512-XQP4u67mBfrcRRfdyT3yvOAlCYlC0fERQOt9wwinZVALcj0BNO+7d7U1SVxzbb6RhXGEQ+xUgSIXxKXuHBZ0xw==
typescript@^5:
version "5.0.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b"
integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==
typical@^4.0.0:
version "4.0.0"
@ -7318,6 +7319,11 @@ ws@7.4.6:
resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c"
integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==
ws@8.2.3:
version "8.2.3"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba"
integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==
ws@^3.0.0:
version "3.3.3"
resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2"