Use Subgraph & Batched Events #2
@ -1,18 +1,16 @@
|
||||
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||
import { AES, HmacSHA256, enc } from 'crypto-js'
|
||||
import { isEmpty } from 'lodash'
|
||||
import { BigNumber, Contract } from 'ethers'
|
||||
import { poseidon } from '@tornado/circomlib'
|
||||
import { decrypt } from 'eth-sig-util'
|
||||
|
||||
const { AES, HmacSHA256, enc } = require('crypto-js')
|
||||
const { isEmpty } = require('lodash')
|
||||
const { BigNumber, Contract } = require('ethers')
|
||||
const { poseidon } = require('@tornado/circomlib')
|
||||
const { decrypt } = require('eth-sig-util')
|
||||
|
||||
const { IndexedDB } = require('./services/idb')
|
||||
const { BatchEventsService } = require('./services/batch')
|
||||
const { getAllCommitments } = require('./services/graph')
|
||||
const { ExtendedProvider } = require('./services/provider')
|
||||
const { POOL_CONTRACT, RPC_LIST, FALLBACK_RPC_LIST, workerEvents, numbers } = require('./services/constants')
|
||||
const { sleep } = require('./services/utilities')
|
||||
const { poolAbi } = require('./services/pool')
|
||||
import { IndexedDB } from './services/idb'
|
||||
import { BatchEventsService } from './services/batch'
|
||||
import { getAllCommitments } from './services/graph'
|
||||
import { ExtendedProvider } from './services/provider'
|
||||
import { POOL_CONTRACT, RPC_LIST, FALLBACK_RPC_LIST, workerEvents, numbers } from './services/constants'
|
||||
import { sleep } from './services/utilities'
|
||||
import { poolAbi } from './services/pool'
|
||||
|
||||
const getProviderWithSigner = (chainId) => {
|
||||
return new ExtendedProvider(RPC_LIST[chainId], chainId, FALLBACK_RPC_LIST[chainId])
|
||||
@ -103,7 +101,7 @@ const getCommitmentBatch = async ({ blockFrom, blockTo, cachedEvents, withCache
|
||||
})
|
||||
|
||||
events.push(...graphEvents)
|
||||
blockFrom = lastSyncBlock + numbers.ONE
|
||||
blockFrom = lastSyncBlock
|
||||
}
|
||||
|
||||
if (!blockTo || blockTo > blockFrom) {
|
||||
|
@ -1,14 +1,13 @@
|
||||
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||
const { isEmpty } = require('lodash')
|
||||
const { BigNumber, Contract } = require('ethers')
|
||||
import { isEmpty } from 'lodash'
|
||||
import { BigNumber, Contract } from 'ethers'
|
||||
|
||||
const { IndexedDB } = require('./services/idb')
|
||||
const { BatchEventsService } = require('./services/batch')
|
||||
const { getAllNullifiers } = require('./services/graph')
|
||||
const { ExtendedProvider } = require('./services/provider')
|
||||
const { POOL_CONTRACT, RPC_LIST, FALLBACK_RPC_LIST, workerEvents, numbers } = require('./services/constants')
|
||||
const { sleep } = require('./services/utilities')
|
||||
const { poolAbi } = require('./services/pool')
|
||||
import { IndexedDB } from './services/idb'
|
||||
import { BatchEventsService } from './services/batch'
|
||||
import { getAllNullifiers } from './services/graph'
|
||||
import { ExtendedProvider } from './services/provider'
|
||||
import { POOL_CONTRACT, RPC_LIST, FALLBACK_RPC_LIST, workerEvents, numbers } from './services/constants'
|
||||
import { sleep } from './services/utilities'
|
||||
import { poolAbi } from './services/pool'
|
||||
|
||||
const getProviderWithSigner = (chainId) => {
|
||||
return new ExtendedProvider(RPC_LIST[chainId], chainId, FALLBACK_RPC_LIST[chainId])
|
||||
@ -138,7 +137,7 @@ const getNullifiers = async (blockFrom) => {
|
||||
})
|
||||
|
||||
events.push(...graphEvents)
|
||||
blockFrom = lastSyncBlock + numbers.ONE
|
||||
blockFrom = lastSyncBlock
|
||||
}
|
||||
|
||||
let nodeEvents = await self.BatchEventsService.getBatchEvents({
|
||||
|
@ -1,6 +1,6 @@
|
||||
const { sleep, getBatches } = require('./utilities')
|
||||
import { sleep, getBatches } from './utilities'
|
||||
|
||||
class BatchEventsService {
|
||||
export class BatchEventsService {
|
||||
constructor({
|
||||
provider,
|
||||
contract,
|
||||
@ -82,6 +82,4 @@ class BatchEventsService {
|
||||
|
||||
return events;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { BatchEventsService }
|
||||
}
|
237
assets/services/bridgeHelper.js
Normal file
237
assets/services/bridgeHelper.js
Normal file
@ -0,0 +1,237 @@
|
||||
export const bridgeAbi = [
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "contract IOmnibridge",
|
||||
name: "_bridge",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "contract IWETH",
|
||||
name: "_weth",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "address",
|
||||
name: "_owner",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
stateMutability: "nonpayable",
|
||||
type: "constructor",
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "address",
|
||||
name: "owner",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
internalType: "bytes",
|
||||
name: "key",
|
||||
type: "bytes",
|
||||
},
|
||||
],
|
||||
name: "PublicKey",
|
||||
type: "event",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "WETH",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "contract IWETH",
|
||||
name: "",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "bridge",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "contract IOmnibridge",
|
||||
name: "",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "_token",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "address",
|
||||
name: "_to",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "claimTokens",
|
||||
outputs: [],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "_token",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "_value",
|
||||
type: "uint256",
|
||||
},
|
||||
{
|
||||
internalType: "bytes",
|
||||
name: "_data",
|
||||
type: "bytes",
|
||||
},
|
||||
],
|
||||
name: "onTokenBridged",
|
||||
outputs: [],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "owner",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
components: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "owner",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "bytes",
|
||||
name: "publicKey",
|
||||
type: "bytes",
|
||||
},
|
||||
],
|
||||
internalType: "struct L1Helper.Account",
|
||||
name: "_account",
|
||||
type: "tuple",
|
||||
},
|
||||
],
|
||||
name: "register",
|
||||
outputs: [],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "_newOwner",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "transferOwnership",
|
||||
outputs: [],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "wrapAndRelayTokens",
|
||||
outputs: [],
|
||||
stateMutability: "payable",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "_receiver",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "bytes",
|
||||
name: "_data",
|
||||
type: "bytes",
|
||||
},
|
||||
],
|
||||
name: "wrapAndRelayTokens",
|
||||
outputs: [],
|
||||
stateMutability: "payable",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "_receiver",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "bytes",
|
||||
name: "_data",
|
||||
type: "bytes",
|
||||
},
|
||||
{
|
||||
components: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "owner",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "bytes",
|
||||
name: "publicKey",
|
||||
type: "bytes",
|
||||
},
|
||||
],
|
||||
internalType: "struct L1Helper.Account",
|
||||
name: "_account",
|
||||
type: "tuple",
|
||||
},
|
||||
],
|
||||
name: "wrapAndRelayTokens",
|
||||
outputs: [],
|
||||
stateMutability: "payable",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "_receiver",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "wrapAndRelayTokens",
|
||||
outputs: [],
|
||||
stateMutability: "payable",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
stateMutability: "payable",
|
||||
type: "receive",
|
||||
},
|
||||
]
|
@ -1,40 +1,40 @@
|
||||
const BSC_CHAIN_ID = 56
|
||||
const XDAI_CHAIN_ID = 100
|
||||
const MAINNET_CHAIN_ID = 1
|
||||
export const BSC_CHAIN_ID = 56
|
||||
export const XDAI_CHAIN_ID = 100
|
||||
export const MAINNET_CHAIN_ID = 1
|
||||
|
||||
const ChainId = {
|
||||
export const ChainId = {
|
||||
BSC: BSC_CHAIN_ID,
|
||||
XDAI: XDAI_CHAIN_ID,
|
||||
MAINNET: MAINNET_CHAIN_ID,
|
||||
}
|
||||
|
||||
const OFFCHAIN_ORACLE_CONTRACT = '0x07D91f5fb9Bf7798734C3f606dB065549F6893bb'
|
||||
export const OFFCHAIN_ORACLE_CONTRACT = '0x07D91f5fb9Bf7798734C3f606dB065549F6893bb'
|
||||
|
||||
const POOL_CONTRACT = {
|
||||
export const POOL_CONTRACT = {
|
||||
[ChainId.XDAI]: '0xD692Fd2D0b2Fbd2e52CFa5B5b9424bC981C30696', // ETH
|
||||
// [ChainId.XDAI]: '0x772F007F13604ac286312C85b9Cd9B2D691B353E', // BNB
|
||||
}
|
||||
const REDGISTRY_CONTRACT = {
|
||||
export const REDGISTRY_CONTRACT = {
|
||||
[ChainId.MAINNET]: '0x58E8dCC13BE9780fC42E8723D8EaD4CF46943dF2',
|
||||
}
|
||||
|
||||
const AGGREGATOR_FACTORY = {
|
||||
export const AGGREGATOR_FACTORY = {
|
||||
[ChainId.MAINNET]: '0xE8F47A78A6D52D317D0D2FFFac56739fE14D1b49',
|
||||
}
|
||||
|
||||
const WRAPPED_TOKEN = {
|
||||
export const WRAPPED_TOKEN = {
|
||||
[ChainId.MAINNET]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // WETH on mainnet
|
||||
[ChainId.XDAI]: '0x6A023CCd1ff6F2045C3309768eAd9E68F978f6e1', // WETH on xdai
|
||||
[ChainId.BSC]: '0xCa8d20f3e0144a72C6B5d576e9Bd3Fd8557E2B04', // WBNB on xdai
|
||||
}
|
||||
|
||||
const RPC_LIST = {
|
||||
export const RPC_LIST = {
|
||||
[ChainId.BSC]: 'https://tornadocash-rpc.com/bsc',
|
||||
[ChainId.MAINNET]: 'https://tornadocash-rpc.com/mainnet',
|
||||
[ChainId.XDAI]: 'https://tornadocash-rpc.com/gnosis',
|
||||
}
|
||||
|
||||
const FALLBACK_RPC_LIST = {
|
||||
export const FALLBACK_RPC_LIST = {
|
||||
[ChainId.BSC]: [
|
||||
'https://binance.nodereal.io',
|
||||
// 'https://rpc.ankr.com/bsc/dbe08b852ba176a8aeac783cc1fa8becaf4f107235dfdae79241063fbf52ca4a',
|
||||
@ -49,52 +49,98 @@ const FALLBACK_RPC_LIST = {
|
||||
],
|
||||
}
|
||||
|
||||
const RPC_WS_LIST = {
|
||||
export const RPC_WS_LIST = {
|
||||
[ChainId.MAINNET]: 'wss://mainnet.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607',
|
||||
[ChainId.BSC]: 'wss://bsc-mainnet.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607',
|
||||
[ChainId.XDAI]: 'wss://gnosis-mainnet.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607',
|
||||
}
|
||||
|
||||
const MULTICALL = {
|
||||
export const MULTICALL = {
|
||||
[ChainId.BSC]: '0xf072f255A3324198C7F653237B44E1C4e66f8C42',
|
||||
[ChainId.XDAI]: '0x8677b93D543d0217B32B8FDc20F2316E138D619B',
|
||||
[ChainId.MAINNET]: '0x1F98415757620B543A52E61c46B32eB19261F984',
|
||||
}
|
||||
|
||||
const BRIDGE_PROXY = {
|
||||
export const BRIDGE_PROXY = {
|
||||
[ChainId.BSC]: '0x05185872898b6f94AA600177EF41B9334B1FA48B',
|
||||
[ChainId.MAINNET]: '0x4c36d2919e407f0cc2ee3c993ccf8ac26d9ce64e',
|
||||
}
|
||||
|
||||
const AMB_BRIDGE = {
|
||||
export const AMB_BRIDGE = {
|
||||
[ChainId.XDAI]: '0x75Df5AF045d91108662D8080fD1FEFAd6aA0bb59', // ETH
|
||||
// [ChainId.XDAI]: '0x162E898bD0aacB578C8D5F8d6ca588c13d2A383F', // BNB
|
||||
[ChainId.MAINNET]: '0x162E898bD0aacB578C8D5F8d6ca588c13d2A383F',
|
||||
}
|
||||
|
||||
const BRIDGE_HELPER = {
|
||||
export const BRIDGE_HELPER = {
|
||||
[ChainId.MAINNET]: '0xCa0840578f57fE71599D29375e16783424023357',
|
||||
[ChainId.BSC]: '0x8845F740F8B01bC7D9A4C82a6fD4A60320c07AF1',
|
||||
}
|
||||
|
||||
const BRIDGE_FEE_MANAGER = {
|
||||
export const BRIDGE_FEE_MANAGER = {
|
||||
[ChainId.XDAI]: '0x5dbC897aEf6B18394D845A922BF107FA98E3AC55',
|
||||
}
|
||||
|
||||
const FOREIGN_OMNIBRIDGE = {
|
||||
export const FOREIGN_OMNIBRIDGE = {
|
||||
[ChainId.MAINNET]: '0x88ad09518695c6c3712AC10a214bE5109a655671',
|
||||
}
|
||||
|
||||
const OMNIBRIDGE = {
|
||||
export const OMNIBRIDGE = {
|
||||
[ChainId.XDAI]: '0xf6A78083ca3e2a662D6dd1703c939c8aCE2e268d',
|
||||
}
|
||||
|
||||
const SANCTION_LIST = {
|
||||
export const SANCTION_LIST = {
|
||||
[ChainId.MAINNET]: '0x40C57923924B5c5c5455c48D93317139ADDaC8fb',
|
||||
}
|
||||
|
||||
export const CHAINS = {
|
||||
[ChainId.XDAI]: {
|
||||
symbol: 'XDAI',
|
||||
name: 'xdai',
|
||||
shortName: 'xdai',
|
||||
icon: 'ethereum',
|
||||
network: 'XDAI',
|
||||
blockDuration: 3000, // ms
|
||||
deployBlock: 19097755, // ETH
|
||||
// deployBlock: 20446605, // BNB
|
||||
blockGasLimit: 144000000, // rpc block gas limit
|
||||
hexChainId: '0x64',
|
||||
isEipSupported: false,
|
||||
ensSubdomainKey: 'gnosis-nova',
|
||||
blockExplorerUrl: 'https://gnosisscan.io'
|
||||
},
|
||||
[ChainId.MAINNET]: {
|
||||
symbol: 'ETH',
|
||||
name: 'ethereum',
|
||||
shortName: 'eth',
|
||||
icon: 'ethereum',
|
||||
network: 'Mainnet',
|
||||
deployBlock: 13494216,
|
||||
blockDuration: 15000,
|
||||
blockGasLimit: 144000000,
|
||||
hexChainId: '0x1',
|
||||
isEipSupported: true,
|
||||
ensSubdomainKey: 'mainnet-tornado',
|
||||
blockExplorerUrl: 'https://etherscan.io'
|
||||
},
|
||||
[ChainId.BSC]: {
|
||||
symbol: 'BNB',
|
||||
name: 'bsc',
|
||||
shortName: 'bsc',
|
||||
icon: 'binance',
|
||||
network: 'BSC',
|
||||
deployBlock: 14931075,
|
||||
blockDuration: 3000,
|
||||
blockGasLimit: 144000000,
|
||||
hexChainId: '0x38',
|
||||
isEipSupported: false,
|
||||
ensSubdomainKey: 'bsc-tornado',
|
||||
blockExplorerUrl: 'https://bscscan.com'
|
||||
},
|
||||
}
|
||||
|
||||
const workerEvents = {
|
||||
|
||||
export const workerEvents = {
|
||||
INIT_WORKER: 'initWorker',
|
||||
GET_COMMITMENT_EVENTS: 'get_commitment_events',
|
||||
// nullifier
|
||||
@ -112,7 +158,7 @@ const workerEvents = {
|
||||
SAVE_LAST_SYNC_BLOCK: 'save_last_sync_block',
|
||||
}
|
||||
|
||||
const numbers = {
|
||||
export const numbers = {
|
||||
ZERO: 0,
|
||||
TWO: 2,
|
||||
ONE: 1,
|
||||
@ -128,13 +174,4 @@ const numbers = {
|
||||
DECRYPT_WORKERS_COUNT: 8,
|
||||
MIN_BLOCKS_INTERVAL_LINE: 200000,
|
||||
EPHEM_PUBLIC_KEY_BUF_LENGTH: 56,
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
ChainId,
|
||||
POOL_CONTRACT,
|
||||
RPC_LIST,
|
||||
FALLBACK_RPC_LIST,
|
||||
workerEvents,
|
||||
numbers
|
||||
}
|
||||
}
|
@ -1,8 +1,11 @@
|
||||
const { isEmpty } = require('lodash')
|
||||
const { ApolloClient, InMemoryCache, gql } = require('@apollo/client/core')
|
||||
import { isEmpty } from 'lodash'
|
||||
import { ApolloClient, InMemoryCache, gql } from '@apollo/client/core'
|
||||
import { utils } from 'ethers'
|
||||
|
||||
const { GET_COMMITMENT, GET_NULLIFIER } = require('./queries')
|
||||
const { ChainId, numbers } = require('../constants')
|
||||
import { GET_ACCOUNTS, GET_COMMITMENT, GET_NULLIFIER } from './queries'
|
||||
import { ChainId, numbers } from '../constants'
|
||||
|
||||
const { getAddress } = utils
|
||||
|
||||
const first = 1000
|
||||
const breakLength = 900
|
||||
@ -23,7 +26,91 @@ const client = new ApolloClient({
|
||||
cache: new InMemoryCache(),
|
||||
})
|
||||
|
||||
async function getCommitments({ fromBlock, chainId }) {
|
||||
export async function getAccounts({ fromBlock, chainId }) {
|
||||
const { data } = await client.query({
|
||||
context: {
|
||||
chainId,
|
||||
},
|
||||
query: gql(GET_ACCOUNTS),
|
||||
variables: { first, fromBlock },
|
||||
})
|
||||
|
||||
if (!data) {
|
||||
return {
|
||||
results: [],
|
||||
lastSyncBlock: data._meta.block.number
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
results: data.accounts,
|
||||
lastSyncBlock: data._meta.block.number
|
||||
}
|
||||
}
|
||||
|
||||
export async function getAllAccounts({ fromBlock, toBlock, chainId }) {
|
||||
try {
|
||||
let accounts = []
|
||||
let lastSyncBlock
|
||||
|
||||
while (true) {
|
||||
let { results, lastSyncBlock: lastBlock } = await getAccounts({ fromBlock, chainId })
|
||||
|
||||
lastSyncBlock = lastBlock
|
||||
|
||||
if (isEmpty(results)) {
|
||||
break
|
||||
}
|
||||
|
||||
if (results.length < breakLength) {
|
||||
accounts = accounts.concat(results)
|
||||
break
|
||||
}
|
||||
|
||||
const [lastEvent] = results.slice(-numbers.ONE)
|
||||
|
||||
results = results.filter((e) => e.blockNumber !== lastEvent.blockNumber)
|
||||
fromBlock = Number(lastEvent.blockNumber)
|
||||
|
||||
accounts = accounts.concat(results)
|
||||
|
||||
if (toBlock && fromBlock >= Number(toBlock)) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!accounts) {
|
||||
return {
|
||||
lastSyncBlock,
|
||||
events: [],
|
||||
}
|
||||
}
|
||||
|
||||
const data = accounts.map((e) => ({
|
||||
key: e.key,
|
||||
owner: getAddress(e.owner),
|
||||
blockNumber: Number(e.blockNumber),
|
||||
}))
|
||||
|
||||
const [lastEvent] = data.slice(-numbers.ONE)
|
||||
|
||||
return {
|
||||
events: data,
|
||||
lastSyncBlock: (lastEvent && lastEvent.blockNumber >= lastSyncBlock)
|
||||
? lastEvent.blockNumber + numbers.ONE
|
||||
: lastSyncBlock,
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Error from getAllAccounts')
|
||||
console.log(err)
|
||||
return {
|
||||
lastSyncBlock: '',
|
||||
events: [],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function getCommitments({ fromBlock, chainId }) {
|
||||
const { data } = await client.query({
|
||||
context: {
|
||||
chainId,
|
||||
@ -45,7 +132,7 @@ async function getCommitments({ fromBlock, chainId }) {
|
||||
}
|
||||
}
|
||||
|
||||
async function getAllCommitments({ fromBlock, toBlock, chainId }) {
|
||||
export async function getAllCommitments({ fromBlock, toBlock, chainId }) {
|
||||
try {
|
||||
let commitments = []
|
||||
let lastSyncBlock
|
||||
@ -84,18 +171,18 @@ async function getAllCommitments({ fromBlock, toBlock, chainId }) {
|
||||
}
|
||||
|
||||
const data = commitments.map((e) => ({
|
||||
blockNumber: Number(e.blockNumber),
|
||||
transactionHash: e.transactionHash,
|
||||
index: Number(e.index),
|
||||
commitment: e.commitment,
|
||||
blockNumber: Number(e.blockNumber),
|
||||
encryptedOutput: e.encryptedOutput,
|
||||
transactionHash: e.transactionHash
|
||||
encryptedOutput: e.encryptedOutput
|
||||
}))
|
||||
|
||||
const [lastEvent] = data.slice(-numbers.ONE)
|
||||
|
||||
return {
|
||||
events: data,
|
||||
lastSyncBlock: (lastEvent && lastEvent.blockNumber > lastSyncBlock)
|
||||
lastSyncBlock: (lastEvent && lastEvent.blockNumber >= lastSyncBlock)
|
||||
? lastEvent.blockNumber + numbers.ONE
|
||||
: lastSyncBlock,
|
||||
}
|
||||
@ -109,7 +196,7 @@ async function getAllCommitments({ fromBlock, toBlock, chainId }) {
|
||||
}
|
||||
}
|
||||
|
||||
async function getNullifiers({ fromBlock, chainId }) {
|
||||
export async function getNullifiers({ fromBlock, chainId }) {
|
||||
const { data } = await client.query({
|
||||
context: {
|
||||
chainId,
|
||||
@ -131,7 +218,7 @@ async function getNullifiers({ fromBlock, chainId }) {
|
||||
}
|
||||
}
|
||||
|
||||
async function getAllNullifiers({ fromBlock, chainId }) {
|
||||
export async function getAllNullifiers({ fromBlock, chainId }) {
|
||||
try {
|
||||
let nullifiers = []
|
||||
let lastSyncBlock
|
||||
@ -175,7 +262,7 @@ async function getAllNullifiers({ fromBlock, chainId }) {
|
||||
|
||||
return {
|
||||
events: data,
|
||||
lastSyncBlock: (lastEvent && lastEvent.blockNumber > lastSyncBlock)
|
||||
lastSyncBlock: (lastEvent && lastEvent.blockNumber >= lastSyncBlock)
|
||||
? lastEvent.blockNumber + numbers.ONE
|
||||
: lastSyncBlock,
|
||||
}
|
||||
@ -187,9 +274,4 @@ async function getAllNullifiers({ fromBlock, chainId }) {
|
||||
events: [],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getAllCommitments,
|
||||
getAllNullifiers
|
||||
}
|
@ -1,4 +1,23 @@
|
||||
const GET_COMMITMENT = `
|
||||
export const GET_ACCOUNTS = `
|
||||
query getAccounts($first: Int, $fromBlock: Int) {
|
||||
accounts(first: $first, orderBy: blockNumber, orderDirection: asc, where: {
|
||||
blockNumber_gte: $fromBlock
|
||||
}) {
|
||||
id
|
||||
key
|
||||
owner
|
||||
blockNumber
|
||||
}
|
||||
_meta {
|
||||
block {
|
||||
number
|
||||
}
|
||||
hasIndexingErrors
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const GET_COMMITMENT = `
|
||||
query getCommitment($first: Int, $fromBlock: Int) {
|
||||
commitments(first: $first, orderBy: blockNumber, orderDirection: asc, where: {
|
||||
blockNumber_gte: $fromBlock
|
||||
@ -18,7 +37,7 @@ const GET_COMMITMENT = `
|
||||
}
|
||||
`
|
||||
|
||||
const GET_NULLIFIER = `
|
||||
export const GET_NULLIFIER = `
|
||||
query getNullifier($first: Int, $fromBlock: Int) {
|
||||
nullifiers(first: $first, orderBy: blockNumber, orderDirection: asc, where: {
|
||||
blockNumber_gte: $fromBlock
|
||||
@ -34,6 +53,4 @@ const GET_NULLIFIER = `
|
||||
hasIndexingErrors
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
module.exports = { GET_COMMITMENT, GET_NULLIFIER }
|
||||
`
|
@ -1,12 +1,12 @@
|
||||
const { deleteDB, openDB } = require('idb')
|
||||
import { deleteDB, openDB } from 'idb'
|
||||
|
||||
const VERSION_ERROR = 'less than the existing version'
|
||||
const INDEX_DB_ERROR = 'A mutation operation was attempted on a database that did not allow mutations.'
|
||||
export const VERSION_ERROR = 'less than the existing version'
|
||||
export const INDEX_DB_ERROR = 'A mutation operation was attempted on a database that did not allow mutations.'
|
||||
|
||||
const IDB_VERSION = 9
|
||||
export const IDB_VERSION = 9
|
||||
|
||||
// TODO method for migration, remove indexed
|
||||
class IndexedDB {
|
||||
export class IndexedDB {
|
||||
constructor({ stores, dbName }) {
|
||||
this.dbExists = false
|
||||
this.isBlocked = false
|
||||
@ -220,5 +220,3 @@ class IndexedDB {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { IndexedDB }
|
||||
|
@ -1,4 +1,4 @@
|
||||
const poolAbi = [
|
||||
export const poolAbi = [
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
@ -1037,6 +1037,4 @@ const poolAbi = [
|
||||
stateMutability: "pure",
|
||||
type: "function",
|
||||
},
|
||||
]
|
||||
|
||||
module.exports = { poolAbi }
|
||||
]
|
@ -1,10 +1,10 @@
|
||||
const { ethers } = require('ethers')
|
||||
const { fetchJson } = require('@ethersproject/web')
|
||||
const { numbers } = require('./constants')
|
||||
import { ethers } from 'ethers'
|
||||
import { fetchJson } from 'ethers/lib/utils'
|
||||
import { numbers } from './constants'
|
||||
|
||||
const defaultRetryAttempt = 0
|
||||
|
||||
class ExtendedProvider extends ethers.providers.StaticJsonRpcProvider {
|
||||
export class ExtendedProvider extends ethers.providers.StaticJsonRpcProvider {
|
||||
constructor(url, network, fallbackRpcs) {
|
||||
super(url, network)
|
||||
this.fallbackRpcs = fallbackRpcs
|
||||
@ -83,6 +83,4 @@ class ExtendedProvider extends ethers.providers.StaticJsonRpcProvider {
|
||||
|
||||
// return (data?.includes(ERROR_DATA) || message?.includes(ERROR_MESSAGE)) && code === ERROR_CODE
|
||||
// }
|
||||
}
|
||||
|
||||
module.exports = { ExtendedProvider }
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
const ZERO_ELEMENT = 0
|
||||
export const ZERO_ELEMENT = 0
|
||||
|
||||
function getBatches(array, batchSize) {
|
||||
export function getBatches(array, batchSize) {
|
||||
const batches = []
|
||||
while (array.length) {
|
||||
batches.push(array.splice(ZERO_ELEMENT, batchSize))
|
||||
@ -8,12 +8,6 @@ function getBatches(array, batchSize) {
|
||||
return batches
|
||||
}
|
||||
|
||||
async function sleep(ms) {
|
||||
export async function sleep(ms) {
|
||||
return await new Promise((resolve) => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
ZERO_ELEMENT,
|
||||
getBatches,
|
||||
sleep
|
||||
}
|
25
assets/services/zip.js
Normal file
25
assets/services/zip.js
Normal file
@ -0,0 +1,25 @@
|
||||
import { zip, unzip } from 'fflate'
|
||||
|
||||
export function zipAsync(file) {
|
||||
return new Promise((res, rej) => {
|
||||
zip(file, { mtime: new Date('1/1/1980') }, (err, data) => {
|
||||
if (err) {
|
||||
rej(err);
|
||||
return;
|
||||
}
|
||||
res(data);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function unzipAsync(data) {
|
||||
return new Promise((res, rej) => {
|
||||
unzip(data, {}, (err, data) => {
|
||||
if (err) {
|
||||
rej(err);
|
||||
return;
|
||||
}
|
||||
res(data);
|
||||
});
|
||||
});
|
||||
}
|
285
assets/syncEvents.js
Normal file
285
assets/syncEvents.js
Normal file
@ -0,0 +1,285 @@
|
||||
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()
|
@ -14,7 +14,8 @@
|
||||
"generate": "yarn worker:compile && nuxt generate && yarn copyFile dist/404.html dist/ipfs-404.html",
|
||||
"prepare": "husky install",
|
||||
"ipfs:upload": "node --loader ts-node/esm ipfsUpload.ts",
|
||||
"worker:compile": "webpack"
|
||||
"worker:compile": "webpack",
|
||||
"update:events": "webpack && node ./syncEvents.cjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.4.16",
|
||||
@ -73,6 +74,7 @@
|
||||
"eslint-plugin-prettier": "^3.4.0",
|
||||
"eslint-plugin-promise": "^5.1.0",
|
||||
"eslint-plugin-vue": "^7.16.0",
|
||||
"fflate": "^0.8.2",
|
||||
"form-data": "^4.0.0",
|
||||
"husky": "^6.0.0",
|
||||
"lint-staged": "10.2.11",
|
||||
|
BIN
static/accounts_1.json.zip
Normal file
BIN
static/accounts_1.json.zip
Normal file
Binary file not shown.
BIN
static/commitments_100.json.zip
Normal file
BIN
static/commitments_100.json.zip
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
static/nullifiers_100.json.zip
Normal file
BIN
static/nullifiers_100.json.zip
Normal file
Binary file not shown.
64403
syncEvents.cjs
Normal file
64403
syncEvents.cjs
Normal file
File diff suppressed because one or more lines are too long
@ -1,4 +1,5 @@
|
||||
import path from 'path'
|
||||
import webpack from 'webpack'
|
||||
|
||||
export default [
|
||||
{
|
||||
@ -16,5 +17,37 @@ export default [
|
||||
path: path.resolve('static'),
|
||||
filename: 'nullifier.worker.js',
|
||||
}
|
||||
},
|
||||
{
|
||||
mode: 'production',
|
||||
entry: './assets/syncEvents.js',
|
||||
output: {
|
||||
path: path.resolve('.'),
|
||||
filename: 'syncEvents.cjs',
|
||||
},
|
||||
target: 'node',
|
||||
plugins: [
|
||||
new webpack.BannerPlugin({
|
||||
banner: '#!/usr/bin/env node\n',
|
||||
raw: true
|
||||
})
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.mjs$/,
|
||||
include: /node_modules/,
|
||||
type: 'javascript/auto'
|
||||
}
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'fflate': 'fflate/esm'
|
||||
}
|
||||
},
|
||||
optimization: {
|
||||
minimize: false,
|
||||
}
|
||||
}
|
||||
]
|
@ -6322,6 +6322,11 @@ ffjavascript@^0.2.48:
|
||||
wasmcurves "0.2.2"
|
||||
web-worker "^1.2.0"
|
||||
|
||||
fflate@^0.8.2:
|
||||
version "0.8.2"
|
||||
resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.8.2.tgz#fc8631f5347812ad6028bbe4a2308b2792aa1dea"
|
||||
integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==
|
||||
|
||||
ffwasm@0.0.7:
|
||||
version "0.0.7"
|
||||
resolved "https://registry.yarnpkg.com/ffwasm/-/ffwasm-0.0.7.tgz#23bb9a3537ecc87c0f24fcfb3a9ddd0e86855fff"
|
||||
|
Loading…
x
Reference in New Issue
Block a user