nova-ui/assets/syncEvents.js

285 lines
6.8 KiB
JavaScript

import path from 'path'
import { stat, readFile, writeFile } from 'fs/promises'
import { Contract, providers, utils } from 'ethers'
import { BatchEventsService } from './services/batch'
import { getAllAccounts, getAllCommitments, getAllNullifiers } from './services/graph'
import { POOL_CONTRACT, BRIDGE_HELPER, RPC_LIST, ChainId, CHAINS, numbers } from './services/constants'
import { zipAsync, unzipAsync } from './services/zip'
import { poolAbi } from './services/pool'
import { bridgeAbi } from './services/bridgeHelper'
const { getAddress } = utils
const { StaticJsonRpcProvider } = providers
const EVENT_PATH = './static'
async function existsAsync(fileOrDir) {
try {
await stat(fileOrDir);
return true;
} catch {
return false;
}
}
const getProvider = (chainId) => {
return new StaticJsonRpcProvider({ skipFetchSetup: true, url: RPC_LIST[chainId] }, chainId)
}
const getTornadoPool = (chainId, provider) => {
const TornadoPool = new Contract(POOL_CONTRACT[chainId], poolAbi, provider)
return {
TornadoPool,
BatchEventsService: new BatchEventsService({
provider,
contract: TornadoPool
})
}
}
const getBridgeHelper = (chainId, provider) => {
const BridgeHelper = new Contract(BRIDGE_HELPER[chainId], bridgeAbi, provider)
return {
BridgeHelper,
BridgeEventsService: new BatchEventsService({
provider,
contract: BridgeHelper
})
}
}
const loadEvents = async (fileName, deployedBlock) => {
fileName = fileName.toLowerCase()
const filePath = path.join(EVENT_PATH, fileName + '.zip')
if (!(await existsAsync(filePath))) {
return {
events: [],
lastBlock: deployedBlock
}
}
try {
const data = await readFile(filePath)
const { [fileName]: content } = await unzipAsync(data)
const events = JSON.parse(new TextDecoder().decode(content))
const lastBlock = events && Array.isArray(events) && events[events.length - 1]
? events[events.length - 1].blockNumber
: deployedBlock
return {
events,
lastBlock
}
} catch {
return {
events: [],
lastBlock: deployedBlock
}
}
}
const saveEvents = async (fileName, events) => {
fileName = fileName.toLowerCase()
const filePath = path.join(EVENT_PATH, fileName + '.zip')
const payload = await zipAsync({
[fileName]: new TextEncoder().encode(JSON.stringify(events, null, 2) + '\n')
})
await writeFile(filePath, payload)
}
const syncAccounts = async (chainId, BatchEventsService) => {
const fileName = `accounts_${chainId}.json`
console.log(`Syncing ${fileName}`)
const cachedEvents = await loadEvents(fileName, CHAINS[chainId].deployBlock)
const events = [...cachedEvents.events]
let fromBlock = cachedEvents.lastBlock + numbers.ONE
console.log({
cachedEvents: events.length,
cachedBlock: fromBlock
})
const { events: graphEvents, lastSyncBlock } = await getAllAccounts({
fromBlock,
chainId
})
console.log({
graphEvents: graphEvents.length,
graphBlock: lastSyncBlock
})
if (lastSyncBlock) {
events.push(...graphEvents)
fromBlock = lastSyncBlock
}
let nodeEvents = await BatchEventsService.getBatchEvents({
fromBlock,
type: 'PublicKey'
})
console.log({
nodeEvents: nodeEvents.length,
nodeBlock: nodeEvents && nodeEvents[nodeEvents.length - 1] ? nodeEvents[nodeEvents.length - 1].blockNumber : undefined
})
if (nodeEvents && nodeEvents.length) {
nodeEvents = nodeEvents.map(({ blockNumber, args }) => ({
key: args.key,
owner: getAddress(args.owner),
blockNumber,
}))
events.push(...nodeEvents)
}
await saveEvents(fileName, events)
}
const syncCommitments = async (chainId, BatchEventsService) => {
const fileName = `commitments_${chainId}.json`
console.log(`Syncing ${fileName}`)
const cachedEvents = await loadEvents(fileName, CHAINS[chainId].deployBlock)
const events = [...cachedEvents.events]
let fromBlock = cachedEvents.lastBlock + numbers.ONE
console.log({
cachedEvents: events.length,
cachedBlock: fromBlock
})
const { events: graphEvents, lastSyncBlock } = await getAllCommitments({
fromBlock,
chainId
})
console.log({
graphEvents: graphEvents.length,
graphBlock: lastSyncBlock
})
if (lastSyncBlock) {
events.push(...graphEvents)
fromBlock = lastSyncBlock
}
let nodeEvents = await BatchEventsService.getBatchEvents({
fromBlock,
type: 'NewCommitment'
})
console.log({
nodeEvents: nodeEvents.length,
nodeBlock: nodeEvents && nodeEvents[nodeEvents.length - 1] ? nodeEvents[nodeEvents.length - 1].blockNumber : undefined
})
if (nodeEvents && nodeEvents.length) {
nodeEvents = nodeEvents.map(({ blockNumber, transactionHash, args }) => ({
blockNumber,
transactionHash,
index: Number(args.index),
commitment: args.commitment,
encryptedOutput: args.encryptedOutput,
}))
events.push(...nodeEvents)
}
await saveEvents(fileName, events)
}
const syncNullifiers = async (chainId, BatchEventsService) => {
const fileName = `nullifiers_${chainId}.json`
console.log(`Syncing ${fileName}`)
const cachedEvents = await loadEvents(fileName, CHAINS[chainId].deployBlock)
const events = [...cachedEvents.events]
let fromBlock = cachedEvents.lastBlock + numbers.ONE
console.log({
cachedEvents: events.length,
cachedBlock: fromBlock
})
const { events: graphEvents, lastSyncBlock } = await getAllNullifiers({
fromBlock,
chainId
})
console.log({
graphEvents: graphEvents.length,
graphBlock: lastSyncBlock
})
if (lastSyncBlock) {
events.push(...graphEvents)
fromBlock = lastSyncBlock
}
let nodeEvents = await BatchEventsService.getBatchEvents({
fromBlock,
type: 'NewNullifier'
})
console.log({
nodeEvents: nodeEvents.length,
nodeBlock: nodeEvents && nodeEvents[nodeEvents.length - 1] ? nodeEvents[nodeEvents.length - 1].blockNumber : undefined
})
if (nodeEvents && nodeEvents.length) {
nodeEvents = nodeEvents.map(({ blockNumber, transactionHash, args }) => ({
blockNumber,
transactionHash,
nullifier: args.nullifier,
}))
events.push(...nodeEvents)
}
await saveEvents(fileName, events)
}
const main = async () => {
const chainId = ChainId.XDAI
const ethChainId = ChainId.MAINNET
const provider = getProvider(chainId)
const ethProvider = getProvider(ethChainId)
const { BatchEventsService } = getTornadoPool(chainId, provider)
const { BridgeEventsService } = getBridgeHelper(ethChainId, ethProvider)
console.log(`Connected with ${chainId}: (block: ${await provider.getBlockNumber()})`)
console.log(`Connected with ${ethChainId}: (block: ${await ethProvider.getBlockNumber()})`)
await syncAccounts(ethChainId, BridgeEventsService)
await syncCommitments(chainId, BatchEventsService)
await syncNullifiers(chainId, BatchEventsService)
}
main()