nova-ui/services/graph/index.ts

332 lines
7.1 KiB
TypeScript
Raw Permalink Normal View History

2022-12-04 09:02:30 +03:00
import { Operation } from '@apollo/client/link/core'
import { ApolloClient, InMemoryCache, gql } from '@apollo/client/core'
import { ChainId } from '@/types'
import { numbers } from '@/constants'
import { isEmpty, toChecksumAddress } from '@/utilities'
import { Params, Accounts, Commitments, Nullifiers } from './@types'
import { _META, GET_ACCOUNTS, GET_REGISTERED, GET_COMMITMENT, GET_NULLIFIER } from './queries'
2022-12-04 09:02:30 +03:00
const first = 1000
const breakLength = 900
const link = (operation: Operation) => {
const { chainId } = operation.getContext()
return CHAIN_GRAPH_URLS[chainId]
}
const CHAIN_GRAPH_URLS: { [chainId in ChainId]: string } = {
[ChainId.BSC]: 'https://api.thegraph.com/subgraphs/name/dan1kov/bsc-tornado-pool-subgraph',
[ChainId.MAINNET]: 'https://api.thegraph.com/subgraphs/name/tornadocash/mainnet-tornado-pool-subgraph',
}
const client = new ApolloClient({
uri: link,
cache: new InMemoryCache(),
})
const registryClient = new ApolloClient({
uri: 'https://api.thegraph.com/subgraphs/name/tornadocash/tornado-relayer-registry',
cache: new InMemoryCache(),
})
async function getRegisters(fromBlock: number) {
const { data } = await registryClient.query({
context: {
chainId: ChainId.MAINNET,
},
query: gql(GET_REGISTERED),
variables: { first, fromBlock },
})
if (!data) {
return []
}
return data.relayers
}
export async function getAccounts({ fromBlock, chainId }: Params): Promise<Accounts> {
const { data } = await client.query({
context: {
chainId,
},
query: gql(GET_ACCOUNTS),
variables: { first, fromBlock },
})
if (!data) {
return []
}
return data.accounts
}
export async function getAllRegisters(fromBlock: number) {
try {
const relayers = await getRegisters(fromBlock)
if (!relayers) {
return { lastSyncBlock: '', events: [] }
}
const lastSyncBlock = await getRegisteredMeta()
return { lastSyncBlock, events: relayers }
} catch {
return { lastSyncBlock: '', events: [] }
}
}
export async function getAllAccounts({ fromBlock, chainId }: Params) {
try {
let accounts: Accounts = []
while (true) {
let result = await getAccounts({ fromBlock, chainId })
if (isEmpty(result)) {
break
}
if (result.length < breakLength) {
accounts = accounts.concat(result)
break
}
const [lastEvent] = result.slice(-numbers.ONE)
result = result.filter((e) => e.blockNumber !== lastEvent.blockNumber)
fromBlock = Number(lastEvent.blockNumber)
accounts = accounts.concat(result)
}
if (!accounts) {
return {
lastSyncBlock: '',
events: [],
}
}
const lastSyncBlock = await getMeta({ chainId })
const data = accounts.map((e) => ({
key: e.key,
owner: toChecksumAddress(e.owner),
blockNumber: Number(e.blockNumber),
}))
const [lastEvent] = data.slice(-numbers.ONE)
return {
events: data,
lastSyncBlock: lastEvent?.blockNumber > lastSyncBlock ? lastEvent.blockNumber + numbers.ONE : lastSyncBlock,
}
} catch {
return {
lastSyncBlock: '',
events: [],
}
}
}
async function getRegisteredMeta() {
try {
const { data } = await registryClient.query({
context: {
chainId: ChainId.MAINNET,
},
query: gql(_META),
})
if (!data) {
return undefined
}
return data._meta.block.number
} catch {
return undefined
}
}
async function getMeta({ chainId }: Params) {
try {
const { data } = await client.query({
context: {
chainId,
},
query: gql(_META),
})
if (!data) {
return undefined
}
return data._meta.block.number
} catch {
return undefined
}
}
export async function getCommitments({ fromBlock, chainId }: Params): Promise<{
results: Commitments,
lastSyncBlock: number
}> {
const { data } = await client.query({
context: {
chainId,
},
query: gql(GET_COMMITMENT),
variables: { first, fromBlock },
})
if (!data) {
return {
results: [],
lastSyncBlock: data._meta.block.number
}
}
return {
results: data.commitments,
lastSyncBlock: data._meta.block.number
}
}
export async function getAllCommitments({ fromBlock, chainId }: Params) {
try {
let commitments: Commitments = []
let lastSyncBlock
while (true) {
let { results, lastSyncBlock: lastBlock } = await getCommitments({ fromBlock, chainId })
lastSyncBlock = lastBlock
if (isEmpty(results)) {
break
}
if (results.length < breakLength) {
commitments = commitments.concat(results)
break
}
const [lastEvent] = results.slice(-numbers.ONE)
results = results.filter((e) => e.blockNumber !== lastEvent.blockNumber)
fromBlock = Number(lastEvent.blockNumber)
commitments = commitments.concat(results)
}
if (!commitments) {
return {
lastSyncBlock,
events: [],
}
}
const data = commitments.map((e) => ({
index: Number(e.index),
commitment: e.commitment,
blockNumber: Number(e.blockNumber),
encryptedOutput: e.encryptedOutput,
transactionHash: e.transactionHash
}))
const [lastEvent] = data.slice(-numbers.ONE)
return {
events: data,
lastSyncBlock: lastEvent?.blockNumber > lastSyncBlock ? lastEvent.blockNumber + numbers.ONE : lastSyncBlock,
}
} catch {
return {
lastSyncBlock: '',
events: [],
}
}
}
export async function getNullifiers({ fromBlock, chainId }: Params): Promise<{
results: Nullifiers,
lastSyncBlock: number
}> {
const { data } = await client.query({
context: {
chainId,
},
query: gql(GET_NULLIFIER),
variables: { first, fromBlock },
})
if (!data) {
return {
results: [],
lastSyncBlock: data._meta.block.number
}
}
return {
results: data.commitments,
lastSyncBlock: data._meta.block.number
}
}
export async function getAllNullifiers({ fromBlock, chainId }: Params) {
try {
let nullifiers: Nullifiers = []
let lastSyncBlock
while (true) {
let { results, lastSyncBlock: lastBlock } = await getNullifiers({ fromBlock, chainId })
lastSyncBlock = lastBlock
if (isEmpty(results)) {
break
}
if (results.length < breakLength) {
nullifiers = nullifiers.concat(results)
break
}
const [lastEvent] = results.slice(-numbers.ONE)
results = results.filter((e) => e.blockNumber !== lastEvent.blockNumber)
fromBlock = Number(lastEvent.blockNumber)
nullifiers = nullifiers.concat(results)
}
if (!nullifiers) {
return {
lastSyncBlock,
events: [],
}
}
const data = nullifiers.map((e) => ({
nullifier: e.nullifier,
blockNumber: Number(e.blockNumber),
transactionHash: e.transactionHash
}))
const [lastEvent] = data.slice(-numbers.ONE)
return {
events: data,
lastSyncBlock: lastEvent?.blockNumber > lastSyncBlock ? lastEvent.blockNumber + numbers.ONE : lastSyncBlock,
}
} catch {
return {
lastSyncBlock: '',
events: [],
}
}
}