2022-06-08 12:45:37 +02:00
|
|
|
import 'dotenv/config'
|
2022-04-22 05:05:56 +02:00
|
|
|
|
2022-06-08 12:45:37 +02:00
|
|
|
import fs from 'fs'
|
|
|
|
import BloomFilter from 'bloomfilter.js'
|
|
|
|
import { MerkleTree } from 'fixed-merkle-tree'
|
|
|
|
import { buildMimcSponge } from 'circomlibjs'
|
2022-04-22 05:05:56 +02:00
|
|
|
|
2022-06-08 12:45:37 +02:00
|
|
|
import networkConfig from '../networkConfig'
|
2022-04-22 05:05:56 +02:00
|
|
|
|
2022-06-08 12:45:37 +02:00
|
|
|
import { loadCachedEvents, save } from './helpers'
|
2022-04-22 05:05:56 +02:00
|
|
|
|
2022-06-08 12:45:37 +02:00
|
|
|
const TREES_FOLDER = 'static/trees'
|
|
|
|
const TREES_PATH = './static/trees/'
|
|
|
|
const EVENTS_PATH = './static/events/'
|
2022-04-22 05:05:56 +02:00
|
|
|
|
2022-06-08 12:45:37 +02:00
|
|
|
const EVENTS = ['deposit']
|
|
|
|
const enabledChains = ['1']
|
2022-04-22 05:05:56 +02:00
|
|
|
let mimcHash
|
|
|
|
|
|
|
|
const trees = {
|
|
|
|
PARTS_COUNT: 4,
|
|
|
|
LEVELS: 20 // const from contract
|
|
|
|
}
|
|
|
|
|
|
|
|
function getName({ path, type, instance, format = '.json', currName = 'eth' }) {
|
|
|
|
return `${path}${type.toLowerCase()}s_${currName}_${instance}${format}`
|
|
|
|
}
|
|
|
|
|
|
|
|
function createTreeZip(netId) {
|
|
|
|
try {
|
|
|
|
const config = networkConfig[`netId${netId}`]
|
|
|
|
const { instanceAddress: CONTRACTS } = config.tokens.eth
|
|
|
|
|
|
|
|
for (const type of EVENTS) {
|
|
|
|
for (const [instance] of Object.entries(CONTRACTS)) {
|
|
|
|
const baseFilename = getName({
|
|
|
|
type,
|
|
|
|
instance,
|
|
|
|
format: '',
|
2022-06-08 12:45:37 +02:00
|
|
|
path: TREES_PATH,
|
2022-04-22 05:05:56 +02:00
|
|
|
currName: config.currencyName.toLowerCase()
|
|
|
|
})
|
|
|
|
|
|
|
|
const treesFolder = fs.readdirSync(TREES_FOLDER)
|
|
|
|
|
|
|
|
treesFolder.forEach((fileName) => {
|
2022-06-08 12:45:37 +02:00
|
|
|
fileName = `${TREES_PATH}${fileName}`
|
2022-04-22 05:05:56 +02:00
|
|
|
const isInstanceFile = !fileName.includes('.zip') && fileName.includes(baseFilename)
|
|
|
|
|
|
|
|
if (isInstanceFile) {
|
2022-06-08 12:45:37 +02:00
|
|
|
save(fileName)
|
2022-04-22 05:05:56 +02:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch {}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function createTree(netId) {
|
|
|
|
try {
|
2022-06-08 12:45:37 +02:00
|
|
|
const { currencyName, tokens, deployedBlock } = networkConfig[`netId${netId}`]
|
2022-04-22 05:05:56 +02:00
|
|
|
|
2022-06-08 12:45:37 +02:00
|
|
|
const currName = currencyName.toLowerCase()
|
|
|
|
const { instanceAddress: CONTRACTS } = tokens.eth
|
2022-04-22 05:05:56 +02:00
|
|
|
|
|
|
|
for (const type of EVENTS) {
|
|
|
|
for (const [instance] of Object.entries(CONTRACTS)) {
|
|
|
|
const filePath = getName({
|
|
|
|
type,
|
|
|
|
instance,
|
|
|
|
currName,
|
|
|
|
format: '',
|
2022-06-08 12:45:37 +02:00
|
|
|
path: TREES_PATH
|
2022-04-22 05:05:56 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
console.log('createTree', { type, instance })
|
|
|
|
|
2022-06-08 12:45:37 +02:00
|
|
|
const { events } = await loadCachedEvents({
|
|
|
|
name: `${type}s_${currName}_${instance}.json`,
|
|
|
|
directory: EVENTS_PATH,
|
|
|
|
deployedBlock
|
|
|
|
})
|
|
|
|
|
2022-04-22 05:05:56 +02:00
|
|
|
console.log('events', events.length)
|
|
|
|
|
|
|
|
const bloom = new BloomFilter(events.length) // to reduce the number of false positives
|
|
|
|
|
|
|
|
const eventsData = events.reduce(
|
|
|
|
(acc, { leafIndex, commitment, ...rest }, i) => {
|
|
|
|
if (leafIndex !== i) {
|
2022-06-08 12:45:37 +02:00
|
|
|
throw new Error(`leafIndex (${leafIndex}) !== i (${i})`)
|
2022-04-22 05:05:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const leave = commitment.toString()
|
|
|
|
acc.leaves.push(leave)
|
|
|
|
acc.metadata[leave] = { ...rest, leafIndex }
|
|
|
|
|
|
|
|
return acc
|
|
|
|
},
|
|
|
|
{ leaves: [], metadata: {} }
|
|
|
|
)
|
|
|
|
|
|
|
|
console.log('leaves', eventsData.leaves.length)
|
|
|
|
|
|
|
|
const tree = new MerkleTree(trees.LEVELS, eventsData.leaves, {
|
|
|
|
zeroElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
|
|
|
|
hashFunction: mimcHash
|
|
|
|
})
|
|
|
|
|
|
|
|
const slices = tree.getTreeSlices(trees.PARTS_COUNT) // [edge(PARTS_COUNT)]
|
|
|
|
|
|
|
|
slices.forEach((slice, index) => {
|
|
|
|
slice.metadata = slice.elements.reduce((acc, curr) => {
|
|
|
|
if (index < trees.PARTS_COUNT - 1) {
|
|
|
|
bloom.add(curr)
|
|
|
|
}
|
|
|
|
acc.push(eventsData.metadata[curr])
|
|
|
|
return acc
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
const sliceJson = JSON.stringify(slice, null, 2) + '\n'
|
|
|
|
fs.writeFileSync(`${filePath}_slice${index + 1}.json`, sliceJson)
|
|
|
|
})
|
|
|
|
|
|
|
|
const bloomCache = bloom.serialize()
|
|
|
|
fs.writeFileSync(`${filePath}_bloom.json`, bloomCache)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (e) {
|
2022-06-08 12:45:37 +02:00
|
|
|
console.error(e.message)
|
2022-04-22 05:05:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function initMimc() {
|
|
|
|
const mimcSponge = await buildMimcSponge()
|
|
|
|
mimcHash = (left, right) => mimcSponge.F.toString(mimcSponge.multiHash([BigInt(left), BigInt(right)]))
|
|
|
|
}
|
|
|
|
|
|
|
|
async function main() {
|
2022-06-08 12:45:37 +02:00
|
|
|
const [, , , chain] = process.argv
|
|
|
|
if (!enabledChains.includes(chain)) {
|
|
|
|
throw new Error(`Supported chain ids ${enabledChains.join(', ')}`)
|
|
|
|
}
|
2022-04-22 05:05:56 +02:00
|
|
|
await initMimc()
|
|
|
|
|
2022-06-08 12:45:37 +02:00
|
|
|
await createTree(chain)
|
|
|
|
await createTreeZip(chain)
|
2022-04-22 05:05:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
main()
|