0.0.11-alpha: more sensible naming

Signed-off-by: T-Hax <>
This commit is contained in:
T-Hax 2023-05-13 19:55:47 +00:00
parent d1d23f252a
commit cd64bc0f63
5 changed files with 71 additions and 63 deletions

View File

@ -6,7 +6,7 @@ import { TornadoInstance, TornadoProxy } from './deth'
// Monorepo
import { RelayerProperties as RelayerDataProperties } from '@tornado/sdk-data'
import { ZKDepositData, InputFor } from '@tornado/sdk-crypto'
import { DepositInfo, InputFor } from '@tornado/sdk-crypto'
// External imports
import { TransactionRequest } from '@ethersproject/abstract-provider'
@ -174,58 +174,59 @@ export class Core extends Synchronizer {
return Contracts.getProxy(String(this.chain.id), this.chain.provider)
}
async buildDepositProof(
async createDepositProof(
instance: TornadoInstance,
relayerProperties: RelayerProperties,
recipientAddress: string,
zkDepositsData: ZKDepositData,
depositInfo: DepositInfo,
options?: Options.Core.BuildDepositProof
): Promise<Array<string>> {
return (
await this.buildDepositProofs(
await this.createDepositProofs(
instance,
relayerProperties,
[recipientAddress],
[zkDepositsData],
[depositInfo],
options
)
)[0]
}
// TODO: Abstract out verification parts of this and provide it as a standalone service in crypto or somewhere else
/**
* @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. 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 depositInfo 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 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(
async createDepositProofs(
instance: TornadoInstance,
relayerProperties: RelayerProperties,
recipientAddresses: Array<string>,
zkDepositsData: Array<ZKDepositData>,
depositInfo: Array<DepositInfo>,
options?: Options.Core.BuildDepositProof
): Promise<Array<Array<string>>> {
this._checkProvider('buildDepositProofs')
this._checkProvider('createDepositProofs')
// Extract commitments and nullifier hashes
const hexCommitments: string[] = []
const hexNullifierHashes: string[] = []
const purchaseAmounts =
options?.ethPurchaseAmounts ?? new Array(zkDepositsData.length).fill(BigNumber.from(0))
options?.ethPurchaseAmounts ?? new Array(depositInfo.length).fill(BigNumber.from(0))
if (zkDepositsData.length !== recipientAddresses.length)
if (depositInfo.length !== recipientAddresses.length)
throw ErrorUtils.getError(
'Core.buildDepositProofs: the number of recipients must equal the length of zkDepositsData.'
'Core.createDepositProofs: the number of recipients must equal the length of depositInfo.'
)
if (zkDepositsData.length !== purchaseAmounts.length)
if (depositInfo.length !== purchaseAmounts.length)
throw ErrorUtils.getError(
'Core.buildDepositProofs: if purchase amounts is specified, it must equal the length of zkDepositsData.'
'Core.createDepositProofs: if purchase amounts is specified, it must equal the length of depositInfo.'
)
zkDepositsData.forEach((deposit) => {
depositInfo.forEach((deposit) => {
hexCommitments.push(deposit.hexCommitment)
hexNullifierHashes.push(deposit.hexNullifierHash)
})
@ -258,7 +259,7 @@ export class Core extends Synchronizer {
// Also add the invalid commitments. We can do leafIndices[i] because the matched one are concatenated
// at the start
for (let i = 0, len = zkDepositsData.length; i < len; i++) {
for (let i = 0, len = depositInfo.length; i < len; i++) {
if (!leafIndices[i]) invalidCommitments.push(hexCommitments[i])
if (checkSpent && checkSpentArray![i]) spentNotes.push(hexNullifierHashes[i])
}
@ -269,7 +270,7 @@ export class Core extends Synchronizer {
if (commitmentsAreInvalid || notesAreSpent)
throw ErrorUtils.getError(
`Core.buildDepositProofs: ` +
`Core.createDepositProofs: ` +
(commitmentsAreInvalid
? `following commitments are invalid:\n\n${invalidCommitments.join('\n')}\n\n`
: '') +
@ -294,7 +295,7 @@ export class Core extends Synchronizer {
// Check whether the root is valid
if (checkKnownRoot && !(await instance.isKnownRoot(root)))
throw ErrorUtils.getError(
'Core.buildDepositProofs: the merkle tree created is not valid, something went wrong with syncing.'
'Core.createDepositProofs: the merkle tree created is not valid, something went wrong with syncing.'
)
// Rest of note invariant arguments
@ -319,7 +320,7 @@ export class Core extends Synchronizer {
if (!tokenPrice && !native)
throw ErrorUtils.getError(
'Core.buildDepositProofs: a token price MUST be supplied if the token withdrawn is not native.'
'Core.createDepositProofs: a token price MUST be supplied if the token withdrawn is not native.'
)
this.emit(
@ -335,13 +336,13 @@ export class Core extends Synchronizer {
)
// Compute proofs
for (let i = 0, len = zkDepositsData.length; i < len; i++) {
for (let i = 0, len = depositInfo.length; i < len; i++) {
inputsForProofs.push({
public: {
root: root,
tree: merkleTree,
leafIndex: leafIndices[i],
hexNullifierHash: zkDepositsData[i].hexNullifierHash,
hexNullifierHash: depositInfo[i].hexNullifierHash,
recipientAddress: recipientAddresses[i],
relayerAddress: relayerProperties.address,
fee: this._calcWithdrawalFee(
@ -358,8 +359,8 @@ export class Core extends Synchronizer {
refund: purchaseAmounts[i] ? bigInt(purchaseAmounts[i].toString()) : bigInt(0)
},
private: {
nullifier: zkDepositsData[i].nullifier,
secret: zkDepositsData[i].secret
nullifier: depositInfo[i].nullifier,
secret: depositInfo[i].secret
}
})
}
@ -447,7 +448,7 @@ export class Core extends Synchronizer {
async loadNotes(
indexes?: Array<number>,
keys?: Partial<Keys.InstanceLookup>
): Promise<Array<ZKDepositData>> {
): Promise<Array<DepositInfo>> {
const rows = await Cache.loadContents<Docs.Note>('DepositNotes')
let docs: Array<Docs.Note | undefined> = []
@ -472,11 +473,11 @@ export class Core extends Synchronizer {
return this.parseNotes(notes)
}
parseNotes(notes: Array<string>): Array<ZKDepositData> {
parseNotes(notes: Array<string>): Array<DepositInfo> {
return notes.map((note) => Primitives.parseNote(note))
}
parseNote(note: string): ZKDepositData {
parseNote(note: string): DepositInfo {
return this.parseNotes([note])[0]
}
@ -573,10 +574,10 @@ export class Core extends Synchronizer {
* @param options Whether or not to populate the transactions (only in the sense of encoding transaction data), and whether to backup notes and invoices. Defaults: `depositsPerInstance = [1], doNotPopulate = false, backup { notes = true, invoices = false }` Deposits per instance are hardcoded to 1, since we're doing a single transaction.
* @returns A promise which resolves to the created transaction.
*/
buildDepositTransaction(instance: TornadoInstance, options?: Options.Core.Deposit): Transactions.Deposit {
createDepositTransaction(instance: TornadoInstance, options?: Options.Core.Deposit): Transactions.Deposit {
let opts: Options.Core.Deposit = options ?? {}
opts.depositsPerInstance = [1]
return this.buildDepositTransactions([instance], opts)[0]
return this.createDepositTransactions([instance], opts)[0]
}
/**
@ -586,11 +587,11 @@ export class Core extends Synchronizer {
* @returns A promise which resolves to the created transactions.
* @todo TODO: Maybe this should be sync and deposit backups should be async somewhere else
*/
buildDepositTransactions(
createDepositTransactions(
instances: Array<TornadoInstance>,
options?: Options.Core.Deposit
): Array<Transactions.Deposit> {
this._checkProvider('buildDepositTransactions')
this._checkProvider('createDepositTransactions')
const depositsPerInstance = options?.depositsPerInstance ?? new Array<number>(instances.length).fill(1)
@ -598,7 +599,7 @@ export class Core extends Synchronizer {
if (depositsPerInstance.length != instances.length)
throw ErrorUtils.getError(
'Core.buildDepositTx: number of deposit amount elements must equal the number of instances!'
'Core.createDepositTx: number of deposit amount elements must equal the number of instances!'
)
const chainId = this.chain.id

View File

@ -132,7 +132,7 @@ export namespace InputFor {
*/
type __InputAliasDelimiter = null
export type ZKDepositData = OutputOf.CreateDeposit
export type DepositInfo = OutputOf.CreateDeposit
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SETUP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
@ -174,7 +174,7 @@ export namespace Primitives {
return HexUtils.bufferToHex(msg, 62)
}
export function parseNote(hexNote: string): ZKDepositData {
export function parseNote(hexNote: string): DepositInfo {
const _hexNote = hexNote.split('_')[1] ?? hexNote
const buffer = Buffer.from(_hexNote.slice(2), 'hex')
return createDeposit({
@ -190,7 +190,7 @@ export namespace Primitives {
nullifier: NumberUtils.randomBigInteger(31),
secret: NumberUtils.randomBigInteger(31)
}
): ZKDepositData {
): DepositInfo {
// @ts-expect-error
let preimage = Buffer.concat([input.nullifier.leInt2Buff(31), input.secret.leInt2Buff(31)])
let commitment = calcPedersenHash({ msg: preimage })

View File

@ -64,7 +64,7 @@ export interface RelayerProperties {
export namespace Options {
export interface Cache {
adapter?: string
cachePath?: string
cacheDirPath?: string
persistent?: boolean
}
}
@ -129,13 +129,13 @@ export namespace Files {
}
}
export async function wipeCache(prompt: boolean = true, cachePath?: string): Promise<void> {
const dir = await opendir(getCachePath('', cachePath))
export async function wipeCache(prompt: boolean = true, cacheDirPath?: string): Promise<void> {
const dir = await opendir(getCachePath('', cacheDirPath))
const toRemove: string[] = []
const userInput = createInterface({ input: process.stdin, output: process.stdout })
for await (const entry of dir) {
if (entry.name.match('(Deposit.*)|(Withdrawal.*)|(Note.*)|(Invoice.*)'))
toRemove.push(getCachePath(entry.name, cachePath))
toRemove.push(getCachePath(entry.name, cacheDirPath))
}
if (toRemove.length != 0) {
if (prompt) {
@ -643,13 +643,15 @@ export namespace Cache {
private _path: string
name: string
isOpen: boolean
db: PouchDB.Database<T>
private _unzip(cachePath?: string): void {
private _unzip(cacheDirPath?: string): void {
if (existsSync(this._path + '.tar.gz')) {
if (existsSync(this._path)) {
throw ErrorUtils.getError(`Can't load both ${this.name} and ${this.name + '.tar.gz'}, remove one!`)
} else Files.gunzipSync(this._path, Files.getCachePath('', cachePath))
} else Files.gunzipSync(this._path, Files.getCachePath('', cacheDirPath))
}
}
@ -664,18 +666,20 @@ export namespace Cache {
const dbAdapter = options?.adapter ?? (options?.persistent === false ? 'memory' : 'leveldb')
if (options?.cachePath)
if (options.cachePath.charAt(options.cachePath.length - 1) != '/') options.cachePath += '/'
if (options?.cacheDirPath)
if (options.cacheDirPath.charAt(options.cacheDirPath.length - 1) != '/') options.cacheDirPath += '/'
if (!Files.cacheDirExists(options?.cachePath)) Files.makeCacheDir()
if (!Files.cacheDirExists(options?.cacheDirPath)) Files.makeCacheDir()
this._path = Files.getCachePath(name, options?.cachePath)
this._path = Files.getCachePath(name, options?.cacheDirPath)
this._adapter = dbAdapter
this._unzip(options?.cachePath)
this._unzip(options?.cacheDirPath)
this.db = new PouchDB<T>(this._path, { adapter: dbAdapter })
this.isOpen = true
}
async zip(outDirPath?: string, close: boolean = false): Promise<void> {
@ -686,6 +690,8 @@ export namespace Cache {
Files.gzipSync(this._path, (outDirPath ?? Files.parentPath(this._path)) + this.name)
if (!close) this.db = new PouchDB<T>(this._path, { adapter: this._adapter })
this.isOpen = !close
}
async get(keys: Array<any>): Promise<T> {
@ -752,6 +758,7 @@ export namespace Cache {
}
}>
// TODO: This logic needs improvement
export async function loadContents<T extends Docs.Base>(
nameOfContent: string,
full: boolean = true,

View File

@ -14,7 +14,7 @@ async function main() {
await core.connect(new providers.JsonRpcProvider("https://some.rpc.url"))
// Build tx (synchronous)
const tx = core.buildDepositTransaction(core.getInstance("usdc", "100"))
const tx = core.createDepositTransaction(core.getInstance("usdc", "100"))
// Print the tx to console
console.log(tx)
@ -69,7 +69,7 @@ async function main() {
}))[0]
// Now build the proof
const proof = await core.buildDepositProof(instance, relayer.properties, receiverAddress, note, {
const proof = await core.createDepositProof(instance, relayer.properties, receiverAddress, note, {
// Defaults after the function populates as a showcase
// You can also leave all of this out and it will set it by itself
checkNotesSpent: true,

View File

@ -215,11 +215,11 @@ describe('Core', () => {
dai = dai.connect(daiWhaleSigner)
})
it('buildDepositTransaction: build a single eth deposit tx and succeed', async () => {
it('createDepositTransaction: build a single eth deposit tx and succeed', async () => {
const initBal = await needsMoney.getBalance()
// Build tx and load cache for this test
const tx = core.buildDepositTransaction(smallestEth)
const tx = core.createDepositTransaction(smallestEth)
// Listen to deposit events
core.listenForDeposits(smallestEth)
@ -246,14 +246,14 @@ describe('Core', () => {
expect(endBal).to.be.lte(parseUnits('999.9'))
}).timeout(0)
it('buildDepositProof: it should be able to build an eth proof', async () => {
it('createDepositProof: it should be able to build an eth proof', async () => {
// Get all of the notes
const notes = await core.loadNotes()
// Build proof
let proof: any
proof = await core.buildDepositProof(
proof = await core.createDepositProof(
smallestEth,
{
address: withdrawerAddress
@ -279,7 +279,7 @@ describe('Core', () => {
).to.changeEtherBalance(needsMoney, ethDelta)
}).timeout(0)
it('buildDepositTransaction: build a single token deposit tx and succeed', async () => {
it('createDepositTransaction: build a single token deposit tx and succeed', async () => {
// Prep deposit amount, proxy for approval, cache, bal for comp
const depositAmount = parseUnits('100000')
const proxy = core.getProxy()
@ -296,7 +296,7 @@ describe('Core', () => {
dai = dai.connect(needsMoney)
const tx = core.buildDepositTransaction(dai100K)
const tx = core.createDepositTransaction(dai100K)
// Approve dai for the proxy first (transferFrom)
await dai.approve(proxy.address, depositAmount)
@ -322,7 +322,7 @@ describe('Core', () => {
expect(await dai.balanceOf(needsMoneyAddress)).to.equal(0)
}).timeout(0)
it('buildDepositProof: it should be able to build a token proof', async () => {
it('createDepositProof: it should be able to build a token proof', async () => {
if (!process.env.TEST_RELAYER_DOMAIN) throw ErrorUtils.getError('core.test.ts: Need a relayer name')
// Get all of the notes
@ -344,7 +344,7 @@ describe('Core', () => {
properties.prices.set('dai', BigNumber.from(10).pow(18).div(1800))
// Build proof with relayer properties this time
const proof = await core.buildDepositProof(dai100K, properties, needsMoneyAddress, note, {
const proof = await core.createDepositProof(dai100K, properties, needsMoneyAddress, note, {
// On by default but stating for visibility
checkNotesSpent: true,
checkKnownRoot: true
@ -360,7 +360,7 @@ describe('Core', () => {
).to.changeTokenBalance(dai, needsMoney, daiDelta)
}).timeout(0)
it.only('buildDepositTransactions: multiple eth deposits', async () => {
it.only('createDepositTransactions: multiple eth deposits', async () => {
const instances = core.getInstances(
[0.1, 1, 10, 100].map((el) => {
return { token: 'eth', denomination: el }
@ -372,7 +372,7 @@ describe('Core', () => {
const depositsPer = [1, 1, 2, 1]
const txs = core.buildDepositTransactions(instances, {
const txs = core.createDepositTransactions(instances, {
depositsPerInstance: depositsPer
})
@ -398,7 +398,7 @@ describe('Core', () => {
expect(await needsMoney.getBalance()).to.be.lte(parseUnits('888.8'))
}).timeout(0)
it.only('buildDepositProofs: should be able to withdraw', async () => {
it.only('createDepositProofs: should be able to withdraw', async () => {
// ETH instances
const instances = core.getInstances(
[0.1, 1, 10, 100].map((el) => {
@ -414,7 +414,7 @@ describe('Core', () => {
// Handle all withdrawals
for (let i = 0, len = instances.length; i < len; i++) {
const proofs = await core.buildDepositProofs(
const proofs = await core.createDepositProofs(
instances[i],
{
address: withdrawerAddress
@ -448,7 +448,7 @@ describe('Core', () => {
}
}).timeout(0)
it('buildDepositTransactions: multiple token deposits', async () => {
it('createDepositTransactions: multiple token deposits', async () => {
// Prepare contracts
const denoms = [100, 1000, 10000, 100000]
const proxy = core.getProxy()
@ -475,7 +475,7 @@ describe('Core', () => {
// Build txs
const txs = core.buildDepositTransactions(instances, {
const txs = core.createDepositTransactions(instances, {
depositsPerInstance: depositsPer
})
@ -513,7 +513,7 @@ describe('Core', () => {
expect(await dai.balanceOf(needsMoneyAddress)).to.equal(0)
}).timeout(0)
it('buildDepositProofs: multiple dai withdrawals', async () => {
it('createDepositProofs: multiple dai withdrawals', async () => {
// ETH instances
const denoms = [100, 1000, 10000, 100000]
const instances = core.getInstances(
@ -544,7 +544,7 @@ describe('Core', () => {
// Handle all withdrawals
for (let i = 0, len = instances.length; i < len; i++) {
const proofs = await core.buildDepositProofs(
const proofs = await core.createDepositProofs(
instances[i],
properties,
new Array(depositsPer[i]).fill(needsMoneyAddress),