Compare commits
No commits in common. "master" and "master" have entirely different histories.
@ -1,5 +1,2 @@
|
|||||||
PINATA_API_KEY=
|
PINATA_API_KEY=
|
||||||
PINATA_SECRET_API_KEY=
|
PINATA_SECRET_API_KEY=
|
||||||
|
|
||||||
MAINNET_SUBGRAPH=
|
|
||||||
MAINNET_RPC=
|
|
||||||
46
Dockerfile
46
Dockerfile
@ -1,46 +0,0 @@
|
|||||||
# Dockefile from https://notes.ethereum.org/@GW1ZUbNKR5iRjjKYx6_dJQ/Bk8zsJ9xj
|
|
||||||
# FROM node:22.17.0-bullseye-slim
|
|
||||||
FROM node@sha256:98663a445a21da13827b841d8df7b4d8743d5133e0d7a4e28ec0852140aa1abe
|
|
||||||
|
|
||||||
# install wget, git and necessary certificates so we can install IPFS below
|
|
||||||
RUN apt update && apt install --yes --no-install-recommends wget git apt-transport-https ca-certificates && rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# install IPFS
|
|
||||||
WORKDIR /home/root
|
|
||||||
RUN wget -qO - https://dist.ipfs.tech/kubo/v0.35.0/kubo_v0.35.0_linux-amd64.tar.gz | tar -xvzf - \
|
|
||||||
&& cd kubo \
|
|
||||||
&& ./install.sh \
|
|
||||||
&& cd .. \
|
|
||||||
&& rm -rf kubo
|
|
||||||
RUN ipfs init
|
|
||||||
|
|
||||||
ENV GIT_REPOSITORY=https://codeberg.org/tornadocash/relayers-network-ui.git
|
|
||||||
# From development branch, double check with tornado.ws
|
|
||||||
ENV GIT_COMMIT_HASH=e5f1b6f91c372fc58a7a6eb463e21a62a059db3b
|
|
||||||
|
|
||||||
# clone the repository
|
|
||||||
RUN mkdir /app/
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Simple hack to fetch only commit and nothing more (no need to download 1GB sized repo, only 100MB would be enough)
|
|
||||||
RUN git init && \
|
|
||||||
git remote add origin $GIT_REPOSITORY && \
|
|
||||||
git fetch --depth 1 origin $GIT_COMMIT_HASH && \
|
|
||||||
git checkout $GIT_COMMIT_HASH
|
|
||||||
|
|
||||||
# install, build and prep for deployment
|
|
||||||
RUN yarn install --frozen-lockfile --ignore-scripts
|
|
||||||
RUN yarn build
|
|
||||||
RUN yarn generate
|
|
||||||
|
|
||||||
# add the build output to IPFS and write the hash to a file
|
|
||||||
RUN ipfs add --cid-version 1 --quieter --only-hash --recursive ./dist > ipfs_hash.txt
|
|
||||||
# print the hash for good measure in case someone is looking at the build logs
|
|
||||||
RUN cat ipfs_hash.txt
|
|
||||||
|
|
||||||
# this entrypoint file will execute `ipfs add` of the build output to the docker host's IPFS API endpoint, so we can easily extract the IPFS build out of the docker image
|
|
||||||
RUN printf '#!/bin/sh\nipfs --api /ip4/`getent ahostsv4 host.docker.internal | grep STREAM | head -n 1 | cut -d \ -f 1`/tcp/5001 add --cid-version 1 -r ./dist' >> entrypoint.sh
|
|
||||||
RUN chmod u+x entrypoint.sh
|
|
||||||
|
|
||||||
ENTRYPOINT [ "./entrypoint.sh" ]
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
import { ChainId } from '@/types'
|
|
||||||
|
|
||||||
export const GRAPHQL_LIMIT = 1000
|
|
||||||
|
|
||||||
/**
|
|
||||||
* todo: add support for subgraph on thegraph & API keys
|
|
||||||
*/
|
|
||||||
export const RELAYER_SUBGRAPH_LIST: Record<number, string> = {
|
|
||||||
[ChainId.MAINNET]: process.env.MAINNET_SUBGRAPH ?? 'https://tornadocash-rpc.com/subgraphs/name/tornadocash/tornado-governance',
|
|
||||||
}
|
|
||||||
@ -3,7 +3,6 @@ export * from './link'
|
|||||||
export * from './enums'
|
export * from './enums'
|
||||||
export * from './steps'
|
export * from './steps'
|
||||||
export * from './errors'
|
export * from './errors'
|
||||||
export * from './graph'
|
|
||||||
export * from './relayer'
|
export * from './relayer'
|
||||||
export * from './variables'
|
export * from './variables'
|
||||||
export * from './contracts'
|
export * from './contracts'
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { ChainId } from '@/types'
|
import { ChainId } from '@/types'
|
||||||
|
|
||||||
export const RPC_LIST: Record<number, string> = {
|
export const RPC_LIST: { [chainId in ChainId]: string } = {
|
||||||
[ChainId.MAINNET]: process.env.MAINNET_RPC ?? 'https://rpc.mevblocker.io',
|
[ChainId.MAINNET]: 'https://tornadocash-rpc.com',
|
||||||
}
|
}
|
||||||
|
|||||||
12
package.json
12
package.json
@ -4,17 +4,14 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"nuxt": "cross-env NODE_OPTIONS=\"--max_old_space_size=8192 --openssl-legacy-provider\" nuxt",
|
"dev": "nuxt",
|
||||||
"dev": "yarn nuxt",
|
"build": "nuxt build",
|
||||||
"build": "yarn nuxt build",
|
"start": "nuxt start",
|
||||||
"start": "yarn nuxt start",
|
|
||||||
"lint": "eslint --ext .js,.ts",
|
"lint": "eslint --ext .js,.ts",
|
||||||
"lint:fix": "eslint --ext .js,.ts --quiet --fix",
|
"lint:fix": "eslint --ext .js,.ts --quiet --fix",
|
||||||
"compile": "typechain --target ethers-v5 --out-dir ./_contracts './abi/*.json'",
|
"compile": "typechain --target ethers-v5 --out-dir ./_contracts './abi/*.json'",
|
||||||
"generate": "yarn nuxt generate && cp dist/404.html dist/ipfs-404.html",
|
"generate": "nuxt generate && cp dist/404.html dist/ipfs-404.html",
|
||||||
"prepare": "husky install",
|
"prepare": "husky install",
|
||||||
"docker:build": "docker build -t relayers-network-ui .",
|
|
||||||
"docker:hash": "docker container run --rm -it --entrypoint cat relayers-network-ui /app/ipfs_hash.txt",
|
|
||||||
"ipfs:upload": "node --loader ts-node/esm ipfsUpload.ts"
|
"ipfs:upload": "node --loader ts-node/esm ipfsUpload.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -59,7 +56,6 @@
|
|||||||
"@types/node": "^16.10.9",
|
"@types/node": "^16.10.9",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.28.0",
|
"@typescript-eslint/eslint-plugin": "^4.28.0",
|
||||||
"@typescript-eslint/parser": "^4.28.0",
|
"@typescript-eslint/parser": "^4.28.0",
|
||||||
"cross-env": "^7.0.3",
|
|
||||||
"dotenv": "^10.0.0",
|
"dotenv": "^10.0.0",
|
||||||
"eslint": "^7.29.0",
|
"eslint": "^7.29.0",
|
||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-config-prettier": "^8.3.0",
|
||||||
|
|||||||
@ -7,16 +7,15 @@ async function getEnsOwner(ensName: string, chainId: ChainId) {
|
|||||||
const { provider } = getProvider(chainId)
|
const { provider } = getProvider(chainId)
|
||||||
const ownerAddress = await provider.resolveName(ensName)
|
const ownerAddress = await provider.resolveName(ensName)
|
||||||
|
|
||||||
return ownerAddress ?? undefined
|
return ownerAddress || undefined
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
async function getNameFromHash(ensHash: string) {
|
async function getNameFromHash(ensHash: string) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('https://api.thegraph.com/subgraphs/name/ensdomains/ens', {
|
const response = await fetch('https://tornadocash-rpc.com/subgraphs/name/graphprotocol/ens', {
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
query: `{
|
query: `{
|
||||||
domain(id: "${ensHash}") {
|
domain(id: "${ensHash}") {
|
||||||
@ -34,6 +33,4 @@ async function getNameFromHash(ensHash: string) {
|
|||||||
throw new Error(err.message)
|
throw new Error(err.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
**/
|
export { getEnsOwner, getNameFromHash }
|
||||||
|
|
||||||
export { getEnsOwner }
|
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
import { checkSubdomains, subdomains } from './ensSubdomains'
|
import { checkSubdomains, subdomains } from './ensSubdomains'
|
||||||
import { getEnsOwner } from './ens'
|
import { getEnsOwner, getNameFromHash } from './ens'
|
||||||
|
|
||||||
export const ensService = {
|
export const ensService = {
|
||||||
subdomains,
|
subdomains,
|
||||||
getEnsOwner,
|
getEnsOwner,
|
||||||
checkSubdomains,
|
checkSubdomains,
|
||||||
|
getNameFromHash,
|
||||||
}
|
}
|
||||||
|
|||||||
115
store/relayer.ts
115
store/relayer.ts
@ -5,26 +5,9 @@ import { AddStakeParams, AddStakePermitParams, ChainId, RootState } from '@/type
|
|||||||
import { RelayerMutation, RelayerState } from '@/types/store/relayer'
|
import { RelayerMutation, RelayerState } from '@/types/store/relayer'
|
||||||
|
|
||||||
import { getRelayerRegistry } from '@/contracts'
|
import { getRelayerRegistry } from '@/contracts'
|
||||||
import { DEPLOYED_BLOCK, GRAPHQL_LIMIT, RELAYER_SUBGRAPH_LIST, errors, numbers } from '@/constants'
|
import { DEPLOYED_BLOCK, errors, numbers } from '@/constants'
|
||||||
import { ensService, tornadoRelayerService } from '@/services'
|
import { ensService, tornadoRelayerService } from '@/services'
|
||||||
import { errorParser, fromWei, toDecimalsPlaces } from '@/utilities'
|
import { errorParser, fromWei, toDecimalsPlaces } from '@/utilities'
|
||||||
import { getAddress, parseEther } from 'ethers/lib/utils'
|
|
||||||
import { BigNumber } from 'ethers'
|
|
||||||
|
|
||||||
interface GraphRelayer {
|
|
||||||
address: string
|
|
||||||
ensName: string
|
|
||||||
ensHash: string
|
|
||||||
|
|
||||||
workers: string[]
|
|
||||||
stakeBalance: string
|
|
||||||
blockRegistration: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface GraphRelayerFormatted extends Omit<GraphRelayer, 'stakeBalance' | 'blockRegistration'> {
|
|
||||||
stakeBalance: BigNumber
|
|
||||||
registerBlock: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export const actions: ActionTree<RelayerState, RootState> = {
|
export const actions: ActionTree<RelayerState, RootState> = {
|
||||||
async checkIsRelayerRegistered({ getters, commit }) {
|
async checkIsRelayerRegistered({ getters, commit }) {
|
||||||
@ -41,7 +24,6 @@ export const actions: ActionTree<RelayerState, RootState> = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Unused because block range is too broad
|
|
||||||
async geRelayerWorkers({ getters, commit }) {
|
async geRelayerWorkers({ getters, commit }) {
|
||||||
try {
|
try {
|
||||||
const { walletAddress, chainId } = getters.dependencies
|
const { walletAddress, chainId } = getters.dependencies
|
||||||
@ -69,81 +51,11 @@ export const actions: ActionTree<RelayerState, RootState> = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async getRelayersFromGraph({ getters }) {
|
async getRelayerENSData({ getters, commit, dispatch }, ensHash) {
|
||||||
try {
|
|
||||||
const { chainId } = getters.dependencies
|
|
||||||
|
|
||||||
const graphUrl = RELAYER_SUBGRAPH_LIST[chainId as ChainId]
|
|
||||||
|
|
||||||
const res = await fetch(graphUrl, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
query: `
|
|
||||||
query getRelayers($first: Int) {
|
|
||||||
relayers(first: $first, orderBy: blockRegistration, orderDirection: asc) {
|
|
||||||
address
|
|
||||||
ensName
|
|
||||||
ensHash
|
|
||||||
|
|
||||||
workers
|
|
||||||
stakeBalance
|
|
||||||
blockRegistration
|
|
||||||
}
|
|
||||||
_meta {
|
|
||||||
block {
|
|
||||||
number
|
|
||||||
}
|
|
||||||
hasIndexingErrors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
variables: {
|
|
||||||
first: GRAPHQL_LIMIT,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new Error(`Invalid response from ${graphUrl} ${res.statusText}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
const { data, errors } = await res.json()
|
|
||||||
|
|
||||||
if (errors) {
|
|
||||||
throw new Error(`Error from graph: ${JSON.stringify(errors)}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data?._meta?.hasIndexingErrors) {
|
|
||||||
throw new Error('Subgraph has indexing errors')
|
|
||||||
}
|
|
||||||
|
|
||||||
return (data.relayers as GraphRelayer[]).map(({ address, ensName, ensHash, workers, stakeBalance, blockRegistration }) => {
|
|
||||||
if (!workers.includes(address)) {
|
|
||||||
workers.push(getAddress(address))
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
address: getAddress(address),
|
|
||||||
ensName,
|
|
||||||
ensHash,
|
|
||||||
workers,
|
|
||||||
stakeBalance: parseEther(stakeBalance),
|
|
||||||
registerBlock: Number(blockRegistration),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err)
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async getRelayerENSData({ getters, commit }, ensName) {
|
|
||||||
try {
|
try {
|
||||||
const { chainId } = getters.dependencies
|
const { chainId } = getters.dependencies
|
||||||
|
|
||||||
|
const ensName = await ensService.getNameFromHash(ensHash)
|
||||||
const subdomains = await ensService.checkSubdomains(ensName, chainId)
|
const subdomains = await ensService.checkSubdomains(ensName, chainId)
|
||||||
|
|
||||||
const mainnetSubdomain = subdomains.find((el) => el.chainId === ChainId.MAINNET)
|
const mainnetSubdomain = subdomains.find((el) => el.chainId === ChainId.MAINNET)
|
||||||
@ -162,22 +74,17 @@ export const actions: ActionTree<RelayerState, RootState> = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async getRelayers({ getters, commit, dispatch }) {
|
async getRelayers({ getters, commit }) {
|
||||||
try {
|
try {
|
||||||
const { walletAddress } = getters.dependencies
|
const { walletAddress, chainId } = getters.dependencies
|
||||||
|
|
||||||
const relayers = (await dispatch('getRelayersFromGraph')) as GraphRelayerFormatted[]
|
const registryContract = getRelayerRegistry(chainId)
|
||||||
|
|
||||||
const relayer = relayers.find((r) => r.address === walletAddress)
|
const { balance, ensHash } = await registryContract.callStatic.relayers(walletAddress)
|
||||||
|
|
||||||
if (!relayer) {
|
commit(RelayerMutation.SET_BALANCE, balance)
|
||||||
throw new Error(`No relayer found for ${walletAddress}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
commit(RelayerMutation.SET_WORKERS, relayer.workers)
|
return ensHash
|
||||||
commit(RelayerMutation.SET_BALANCE, relayer.stakeBalance)
|
|
||||||
|
|
||||||
await dispatch('getRelayerENSData', relayer.ensName)
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new Error(err.message)
|
throw new Error(err.message)
|
||||||
}
|
}
|
||||||
@ -191,7 +98,9 @@ export const actions: ActionTree<RelayerState, RootState> = {
|
|||||||
throw new Error(errors.relayer.NOT_REGISTERED)
|
throw new Error(errors.relayer.NOT_REGISTERED)
|
||||||
}
|
}
|
||||||
|
|
||||||
await dispatch('getRelayers')
|
await dispatch('geRelayerWorkers')
|
||||||
|
const ensHash = await dispatch('getRelayers')
|
||||||
|
await dispatch('getRelayerENSData', ensHash)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const errorText = errorParser(err.message, errors.validation.NO_RESPONSE)
|
const errorText = errorParser(err.message, errors.validation.NO_RESPONSE)
|
||||||
|
|
||||||
|
|||||||
16
yarn.lock
16
yarn.lock
@ -3923,13 +3923,6 @@ create-require@^1.1.0, create-require@^1.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
|
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
|
||||||
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
|
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
|
||||||
|
|
||||||
cross-env@^7.0.3:
|
|
||||||
version "7.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
|
|
||||||
integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==
|
|
||||||
dependencies:
|
|
||||||
cross-spawn "^7.0.1"
|
|
||||||
|
|
||||||
cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
|
cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
|
||||||
version "7.0.3"
|
version "7.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
|
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
|
||||||
@ -3939,15 +3932,6 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
|
|||||||
shebang-command "^2.0.0"
|
shebang-command "^2.0.0"
|
||||||
which "^2.0.1"
|
which "^2.0.1"
|
||||||
|
|
||||||
cross-spawn@^7.0.1:
|
|
||||||
version "7.0.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
|
|
||||||
integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
|
|
||||||
dependencies:
|
|
||||||
path-key "^3.1.0"
|
|
||||||
shebang-command "^2.0.0"
|
|
||||||
which "^2.0.1"
|
|
||||||
|
|
||||||
crypto-browserify@^3.11.0:
|
crypto-browserify@^3.11.0:
|
||||||
version "3.12.0"
|
version "3.12.0"
|
||||||
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
|
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user