From 098a4687cf2ebcf1d445437708bacdef2ae7ddad Mon Sep 17 00:00:00 2001 From: Theo Date: Sun, 23 Jul 2023 07:25:11 -0700 Subject: [PATCH] Prepare installation script, config, environment and docker-compose for deployment to v6 version --- .env.example | 4 +- README.md | 114 ++--- docker-compose.test.yml | 42 -- docker-compose.yml | 409 +++++++++++++++--- install.sh | 110 +++++ package.json | 3 +- src/config.ts | 5 +- ...ceOracleABI.ts => OvmGasPriceOracleAbi.ts} | 0 .../{ProxyLightABI.ts => ProxyLightAbi.ts} | 0 ...{TornadoProxyABI.ts => TornadoProxyAbi.ts} | 0 ...ry.ts => OvmGasPriceOracleAbi__factory.ts} | 0 ...__factory.ts => ProxyLightAbi__factory.ts} | 0 ...factory.ts => TornadoProxyAbi__factory.ts} | 0 src/services/tx.service.ts | 4 +- tornado-stream.conf | 15 + tornado.conf | 87 ++++ 16 files changed, 635 insertions(+), 158 deletions(-) delete mode 100644 docker-compose.test.yml create mode 100644 install.sh rename src/contracts/{OvmGasPriceOracleABI.ts => OvmGasPriceOracleAbi.ts} (100%) rename src/contracts/{ProxyLightABI.ts => ProxyLightAbi.ts} (100%) rename src/contracts/{TornadoProxyABI.ts => TornadoProxyAbi.ts} (100%) rename src/contracts/factories/{OvmGasPriceOracleABI__factory.ts => OvmGasPriceOracleAbi__factory.ts} (100%) rename src/contracts/factories/{ProxyLightABI__factory.ts => ProxyLightAbi__factory.ts} (100%) rename src/contracts/factories/{TornadoProxyABI__factory.ts => TornadoProxyAbi__factory.ts} (100%) create mode 100644 tornado-stream.conf create mode 100644 tornado.conf diff --git a/.env.example b/.env.example index f3e3e9b..a7b0521 100644 --- a/.env.example +++ b/.env.example @@ -12,13 +12,13 @@ APP_PORT=8000 # without 0x prefix PRIVATE_KEY= # 0.1 means 0.1%, we recommend 0.1 for sidechains and 0.4 for mainnet -REGULAR_TORNADO_WITHDRAW_FEE=0.1 +RELAYER_FEE=0.1 REWARD_ACCOUNT=0x... CONFIRMATIONS=4 # in GWEI MAX_GAS_PRICE=1000 -BASE_FEE_RESERVE_PERCENTAGE=25 +GAS_BUMP_PERCENTAGE=5 AGGREGATOR=0x8cb1436F64a3c33aD17bb42F94e255c4c0E871b2 # Telegram bot alerts TELEGRAM_NOTIFIER_BOT_TOKEN= diff --git a/README.md b/README.md index 2004eb9..e5dc641 100644 --- a/README.md +++ b/README.md @@ -1,62 +1,80 @@ -# Relayer for Tornado Cash [![Build Status](https://github.com/tornadocash/relayer/workflows/build/badge.svg)](https://github.com/tornadocash/relayer/actions) [![Docker Image Version (latest semver)](https://img.shields.io/docker/v/tornadocash/relayer?logo=docker&logoColor=%23FFFFFF&sort=semver)](https://hub.docker.com/repository/docker/tornadocash/relayer) +# Relayer for Tornado Cash [![Build Status](https://github.com/tornadocash/relayer/workflows/build/badge.svg)](https://github.com/tornadocash/relayer/actions) ![Static Badge](https://img.shields.io/badge/version-6.0.0-blue?logo=docker) -## Deploy with docker-compose +__*Tornado Cash was sanctioned by the US Treasury on 08/08/2022, this makes it illegal for US citizens to interact with Tornado Cash and all of it's associated deployed smart contracts. Please understand the laws where you live and take all necessary steps to protect and anonymize yourself.__ -docker-compose.yml contains a stack that will automatically provision SSL certificates for your domain name and will add -a https redirect to port 80. +__*It is recommended to run your Relayer on a VPS instnace ([Virtual Private Server](https://njal.la/)). Ensure SSH configuration is enabled for security, you can find information about SSH keygen and management [here](https://www.ssh.com/academy/ssh/keygen).__ -1. Download [docker-compose.yml](/docker-compose.yml) and [.env.example](/.env.example) +## Deploy with script and docker-compose -``` -wget https://raw.githubusercontent.com/tornadocash/tornado-relayer/master/docker-compose.yml -wget https://raw.githubusercontent.com/tornadocash/tornado-relayer/master/.env.example -O .env +*The following instructions are for Ubuntu 22.10, other operating systems may vary.* + +#### Installation: + +Just run in terminal: + +```bash +curl -s https://git.tornado.ws/tornadocash/classic-relayer/raw/branch/v6/install.sh | bash ``` -2. Setup environment variables +#### Configuring environments: -- set `NET_ID` (1 for mainnet, [networks list](#compatible-networks)) -- set `HTTP_RPC_URL` rpc url for your ethereum node -- set `ORACLE_RPC_URL` - rpc url for mainnet node for fetching prices(always have to be on mainnet) -- set `PRIVATE_KEY` for your relayer address (without 0x prefix) -- set `VIRTUAL_HOST` and `LETSENCRYPT_HOST` to your domain and add DNS record pointing to your relayer ip address -- set `REGULAR_TORNADO_WITHDRAW_FEE` - fee in % that is used for tornado pool withdrawals -- set `REWARD_ACCOUNT` - eth address that is used to collect fees -- update `AGGREGATOR` if needed - Contract address of aggregator instance. -- update `CONFIRMATIONS` if needed - how many block confirmations to wait before processing an event. Not recommended - to set less than 3 -- update `MAX_GAS_PRICE` if needed - maximum value of gwei value for relayer's transaction -- update `BASE_FEE_RESERVE_PERCENTAGE` if needed - how much in % will the network baseFee increase -- set `TELEGRAM_NOTIFIER_BOT_TOKEN` and `TELEGRAM_NOTIFIER_CHAT_ID` if your want get notify to telegram +1. Go to `tornado-relayer` folder on the server home directory +2. Check environment files: -If you want to use more than 1 eth address for relaying transactions, please add as many `workers` as you want. For -example, you can comment out `worker2` in docker-compose.yml file, but please use a different `PRIVATE_KEY` for each -worker. +​ By default each network is preconfigured the naming of `.env.` -3. Run `docker-compose up -d` +- `.env.eth` for Ethereum Mainnet +- `.env.goerli` for Goerli testnet +- `.env.bsc` for Binance Smart Chain +- `.env.arb` for Arbitrum +- `.env.op` for Optimism +- `.env.gnosis` for Gnosis (xdai) +- `.env.polygon` for Polygon (matic) +- `.env.avax` for Avalanche C-Chain -## V5 Migration Guide +​ 3. Configure (fill) environment files for those networks on which the relayer will be deployed: -This guide is intended to help with migration from Relayer v4 to v5. + - Set `PRIVATE_KEY` to your relayer address (remove the 0x from your private key) to each environment file -1. Stop relayer + - *It is recommended not to reuse the same private keys for each network as a security measure* -``` -docker-compose down -``` + - Set `VIRTUAL_HOST` and `LETSENCRYPT_HOST` a unique subndomain for every network to each environment file -2. Download the latest version of relayer`s docker compose file + - eg: `mainnet.example.com` for Ethereum, `binance.example.com` for Binance etc + - add a A wildcard record DNS record with the value assigned to your instance IP address to configure subdomains -``` -wget https://raw.githubusercontent.com/tornadocash/tornado-relayer/master/docker-compose.yml -``` + - Set `RELAYER_FEE` to what you would like to charge as your fee (remember 0.3% is deducted from your staked relayer balance) -3. Check your environment variables, add new ones if needed + - Set `RPC_URL` to a non-censoring RPC (You can [run your own](https://github.com/feshchenkod/rpc-nodes), or use a [free option](https://chainnodes.org/)) -4. Run updated docker compose file + - Set `ORACLE_RPC_URL` to an Ethereum native RPC endpoint -``` -docker-compose up -d --pull -``` + - Set `REWARD_ACCOUNT` - eth address that is used to collect fees + + - Set `TELEGRAM_NOTIFIER_BOT_TOKEN` and `TELEGRAM_NOTIFIER_CHAT_ID` if your want get notify to telegram + + + + - Update `AGGREGATOR` if needed - Contract address of aggregator instance. + + - Update `CONFIRMATIONS` if needed - how many block confirmations to wait before processing an event. Not recommended + to set less than 3 + + - Update `MAX_GAS_PRICE` if needed - maximum value of gwei value for relayer's transaction + + - Update `GAS_BUMP_PERCENTAGE` if needed - how much in % will the network gas for transaction additionally increased + + **NB!** Don't update these values if you not sure what you doing. + + + +#### Deployment: + +1. Build and deploy the docker source for the configured neworks specified via `--profile `, for example (if you run relayer only for Ethereum Mainnet, Binance Smart Chain and Arbitrum): + + - `docker-compose --profile eth --profile bsc --profile arb up -d` + +2. Visit your domain addresses and check each `/status` endpoint to ensure there is no errors in the `status` fields ## Run locally @@ -75,7 +93,7 @@ curl -X POST -H 'content-type:application/json' --data '' http://127 Relayer should return a job id in uuid v4 format. In that case you will need to add https termination yourself because browsers with default settings will prevent https -tornado.cash UI from submitting your request over http connection +Tornado Cash UI from submitting your request over http connection ## Run geth node @@ -91,13 +109,12 @@ For basic monitoring setup telegram bot and fill variables in .env file Alerts about: - Main relayer currency balance -- Torn balance +- Torn staked balance in relayer contract - Withdraw transactions send errors How to create bot: https://core.telegram.org/bots#3-how-do-i-create-a-bot -How to get chat -id: https://stackoverflow.com/questions/32423837/telegram-bot-how-to-get-a-group-chat-id/32572159#32572159 +How to get chat id: https://stackoverflow.com/questions/32423837/telegram-bot-how-to-get-a-group-chat-id/32572159#32572159 ### Advanced @@ -114,9 +131,8 @@ You can find the guide on how to install the Zabbix server in the [/monitoring/R - Avalanche Mainnet (43114) - Ethereum Goerli (5) + + Disclaimer: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/docker-compose.test.yml b/docker-compose.test.yml deleted file mode 100644 index b1bcc29..0000000 --- a/docker-compose.test.yml +++ /dev/null @@ -1,42 +0,0 @@ -version: '3.7' - -services: - server: - image: tornadocash/relayer - restart: always - command: 'server' - env_file: .env - build: - context: . - dockerfile: Dockerfile - ports: - - '8000:8000' - depends_on: [redis] - - txWorker: - image: tornadocash/relayer - restart: unless-stopped - command: 'txWorker' - env_file: .env - depends_on: [redis] - - healthWorker: - image: tornadocash/relayer - restart: unless-stopped - command: 'healthWorker' - env_file: .env - depends_on: [redis] - - redis: - image: redis - restart: unless-stopped - ports: - - 6379:6379 - environment: - - REDIS_APPENDONLY=yes - - REDIS_APPENDFSYNC=always - volumes: - - redis:/data - -volumes: - redis: diff --git a/docker-compose.yml b/docker-compose.yml index 9474509..f78feb9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,33 +1,95 @@ -version: '3' +version: '2' services: - server: - image: tornadocash/relayer + redis: + image: redis + restart: always + command: [redis-server, --appendonly, 'yes'] + volumes: + - redis:/data + ports: + - '127.0.0.1:6379:6379' + + nginx: + image: nginx:alpine + container_name: nginx + restart: always + ports: + - 80:80 + - 443:443 + volumes: + - conf:/etc/nginx/conf.d + - vhost:/etc/nginx/vhost.d + - html:/usr/share/nginx/html + - certs:/etc/nginx/certs + logging: + driver: none + + dockergen: + image: poma/docker-gen + container_name: dockergen + restart: always + command: -notify-sighup nginx -watch /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf + volumes_from: + - nginx + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + + letsencrypt: + image: jrcs/letsencrypt-nginx-proxy-companion + container_name: letsencrypt + restart: always + environment: + NGINX_DOCKER_GEN_CONTAINER: dockergen + volumes_from: + - nginx + - dockergen + + # ---------------------- ETH Mainnet ----------------------- # + + eth-server: + image: tornadocash/relayer:v6 + profiles: ['eth'] restart: always command: server - env_file: .env + env_file: .env.eth environment: + NET_ID: 1 REDIS_URL: redis://redis/0 nginx_proxy_read_timeout: 600 - VIRTUAL_PORT: ${APP_PORT} depends_on: [redis] - worker1: - image: tornadocash/relayer + eth-healthWorker: + image: tornadocash/relayer:v6 + profiles: ['eth'] restart: always - command: worker - env_file: .env + command: healthWorker + env_file: .env.eth environment: + NET_ID: 1 REDIS_URL: redis://redis/0 - depends_on: [redis] + depends_on: [redis, eth-server] - # worker2: - # image: tornadocash/relayer:mining + eth-txWorker1: + image: tornadocash/relayer:v6 + profiles: ['eth'] + restart: always + command: txWorker + env_file: .env.eth + environment: + NET_ID: 1 + REDIS_URL: redis://redis/0 + depends_on: [redis, eth-server] + + # # This is additional txWorker for ethereum mainnet + # # So you can process transactions from multiple addresses, but before it you need to set up those addresses as txWorkers + # eth-txWorker2: + # image: tornadocash/relayer:v6 + # profiles: [ 'eth' ] # restart: always - # command: worker - # env_file: .env + # command: txWorker + # env_file: .env2.eth # environment: - # PRIVATE_KEY: qwe # REDIS_URL: redis://redis/0 # # this container will proxy *.onion domain to the server container @@ -66,55 +128,284 @@ services: # TELEGRAM_NOTIFIER_BOT_TOKEN: ... # TELEGRAM_NOTIFIER_CHAT_ID: ... - redis: - image: redis + # # this container will send Telegram notifications if specified address doesn't have enough funds + # monitor_mainnet: + # image: peppersec/monitor_eth + # restart: always + # environment: + # TELEGRAM_NOTIFIER_BOT_TOKEN: ... + # TELEGRAM_NOTIFIER_CHAT_ID: ... + # ADDRESS: '0x0000000000000000000000000000000000000000' + # THRESHOLD: 0.5 # ETH + # RPC_URL: https://mainnet.infura.io + # BLOCK_EXPLORER: etherscan.io + + # -------------------------------------------------- # + + # ---------------------- BSC (Binance Smart Chain) ----------------------- # + + bsc-server: + image: tornadocash/relayer:v6 + profiles: ['bsc'] restart: always + command: server + env_file: .env.bsc environment: - - REDIS_APPENDONLY=yes - - REDIS_APPENDFSYNC=always - ports: - - '127.0.0.1:6379:6379' # do not expose redis port - volumes: - - redis:/data + NET_ID: 56 + REDIS_URL: redis://redis/1 + nginx_proxy_read_timeout: 600 + depends_on: [redis] - nginx: - image: nginx:alpine - # container_name: nginx - restart: always - ports: - - 80:80 - - 443:443 - volumes: - - conf:/etc/nginx/conf.d - - vhost:/etc/nginx/vhost.d - - html:/usr/share/nginx/html - - certs:/etc/nginx/certs - logging: - driver: none - - dockergen: - image: poma/docker-gen - container_name: dockergen - restart: always - command: -notify-sighup nginx -watch /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf - volumes: - - conf:/etc/nginx/conf.d - - vhost:/etc/nginx/vhost.d - - html:/usr/share/nginx/html - - certs:/etc/nginx/certs - - /var/run/docker.sock:/var/run/docker.sock:ro - - letsencrypt: - image: jrcs/letsencrypt-nginx-proxy-companion - container_name: letsencrypt + bsc-healthWorker: + image: tornadocash/relayer:v6 + profiles: ['bsc'] restart: always + command: healthWorker + env_file: .env.bsc environment: - NGINX_DOCKER_GEN_CONTAINER: dockergen - volumes: - - conf:/etc/nginx/conf.d - - vhost:/etc/nginx/vhost.d - - html:/usr/share/nginx/html - - certs:/etc/nginx/certs + NET_ID: 56 + REDIS_URL: redis://redis/1 + depends_on: [redis, bsc-server] + + bsc-txWorker1: + image: tornadocash/relayer:v6 + profiles: ['bsc'] + restart: always + command: txWorker + env_file: .env.bsc + environment: + NET_ID: 56 + REDIS_URL: redis://redis/1 + depends_on: [redis, bsc-server] + + # -------------------------------------------------- # + + # ---------------------- Polygon (MATIC) --------------------- # + + polygon-server: + image: tornadocash/relayer:v6 + profiles: ['polygon'] + restart: always + command: server + env_file: .env.polygon + environment: + NET_ID: 137 + REDIS_URL: redis://redis/2 + nginx_proxy_read_timeout: 600 + depends_on: [redis] + + polygon-healthWorker: + image: tornadocash/relayer:v6 + profiles: ['polygon'] + restart: always + command: healthWorker + env_file: .env.polygon + environment: + NET_ID: 137 + REDIS_URL: redis://redis/2 + depends_on: [redis, polygon-server] + + polygon-txWorker1: + image: tornadocash/relayer:v6 + profiles: ['polygon'] + restart: always + command: txWorker + env_file: .env.polygon + environment: + NET_ID: 137 + REDIS_URL: redis://redis/2 + depends_on: [redis, polygon-server] + + # -------------------------------------------------- # + + # ---------------------- Gnosis (XDAI) ---------------------- # + + gnosis-server: + image: tornadocash/relayer:v6 + profiles: ['gnosis'] + restart: always + command: server + env_file: .env.gnosis + environment: + NET_ID: 100 + REDIS_URL: redis://redis/3 + nginx_proxy_read_timeout: 600 + depends_on: [redis] + + gnosis-healthWorker: + image: tornadocash/relayer:v6 + profiles: ['gnosis'] + restart: always + command: healthWorker + env_file: .env.gnosis + environment: + NET_ID: 100 + REDIS_URL: redis://redis/3 + depends_on: [redis, gnosis-server] + + gnosis-txWorker1: + image: tornadocash/relayer:v6 + profiles: ['gnosis'] + restart: always + command: txWorker + env_file: .env.gnosis + environment: + NET_ID: 100 + REDIS_URL: redis://redis/3 + depends_on: [redis, gnosis-server] + + # -------------------------------------------------- # + + # ---------------------- AVAX ---------------------- # + + avax-server: + image: tornadocash/relayer:v6 + profiles: ['avax'] + restart: always + command: server + env_file: .env.avax + environment: + NET_ID: 43114 + REDIS_URL: redis://redis/4 + nginx_proxy_read_timeout: 600 + depends_on: [redis] + + avax-healthWorker: + image: tornadocash/relayer:v6 + profiles: ['avax'] + restart: always + command: healthWorker + env_file: .env.avax + environment: + NET_ID: 43114 + REDIS_URL: redis://redis/4 + depends_on: [redis, avax-server] + + avax-txWorker1: + image: tornadocash/relayer:v6 + profiles: ['avax'] + restart: always + command: txWorker + env_file: .env.avax + environment: + NET_ID: 43114 + REDIS_URL: redis://redis/4 + depends_on: [redis, avax-server] + + # -------------------------------------------------- # + + # ---------------------- OP ------------------------ # + + op-server: + image: tornadocash/relayer:v6 + profiles: ['op'] + restart: always + command: server + env_file: .env.op + environment: + NET_ID: 10 + REDIS_URL: redis://redis/5 + nginx_proxy_read_timeout: 600 + depends_on: [redis] + + op-healthWorker: + image: tornadocash/relayer:v6 + profiles: ['op'] + restart: always + command: healthWorker + env_file: .env.op + environment: + NET_ID: 10 + REDIS_URL: redis://redis/5 + depends_on: [redis, op-server] + + op-txWorker1: + image: tornadocash/relayer:v6 + profiles: ['op'] + restart: always + command: txWorker + env_file: .env.op + environment: + NET_ID: 10 + REDIS_URL: redis://redis/5 + depends_on: [redis, op-server] + + # -------------------------------------------------- # + + # ---------------------- Arbitrum ----------------------- # + + arb-server: + image: tornadocash/relayer:v6 + profiles: ['arb'] + restart: always + command: server + env_file: .env.arb + environment: + NET_ID: 42161 + REDIS_URL: redis://redis/6 + nginx_proxy_read_timeout: 600 + depends_on: [redis] + + arb-healthWorker: + image: tornadocash/relayer:v6 + profiles: ['arb'] + restart: always + command: healthWorker + env_file: .env.arb + environment: + NET_ID: 42161 + REDIS_URL: redis://redis/6 + depends_on: [redis, arb-server] + + arb-txWorker1: + image: tornadocash/relayer:v6 + profiles: ['arb'] + restart: always + command: txWorker + env_file: .env.arb + environment: + NET_ID: 42161 + REDIS_URL: redis://redis/6 + depends_on: [redis, arb-server] + + # -------------------------------------------------- # + + # ---------------------- Goerli (Ethereum Testnet) ---------------------- # + + goerli-server: + image: tornadocash/relayer:v6 + profiles: ['geth'] + restart: always + command: server + env_file: .env.goerli + environment: + NET_ID: 5 + REDIS_URL: redis://redis/7 + nginx_proxy_read_timeout: 600 + depends_on: [redis] + + goerli-healthWorker: + image: tornadocash/relayer:v6 + profiles: ['goerli'] + restart: always + command: healthWorker + env_file: .env.goerli + environment: + NET_ID: 5 + REDIS_URL: redis://redis/7 + depends_on: [redis, goerli-server] + + goerli-txWorker1: + image: tornadocash/relayer:v6 + profiles: ['goerli'] + restart: always + command: txWorker + env_file: .env.goerli + environment: + NET_ID: 5 + REDIS_URL: redis://redis/7 + depends_on: [redis, goerli-server] + # -------------------------------------------------- # volumes: conf: diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..2aa6e3c --- /dev/null +++ b/install.sh @@ -0,0 +1,110 @@ +#!/bin/bash +# Script must be running from root +if [ "$EUID" -ne 0 ]; + then echo "Please run as root"; + exit 1; +fi; + +relayer_soft_git_repo="https://git.tornado.ws/tornadocash/classic-relayer"; + +user_home_dir=$(eval echo ~$USER); +relayer_folder="$user_home_dir/tornado-relayer"; +script_log_file="/tmp/tornado-classic-relayer-installation.log" +if [ -f $script_log_file ]; then rm $script_log_file; fi; + +function echo_log_err(){ + echo $1 1>&2; + echo -e "$1\n" &>> $script_log_file; +} + +function echo_log_err_and_exit(){ + echo_log_err "$1"; + exit 1; +} + +function is_package_installed(){ + if [ $(dpkg-query -W -f='${Status}' $1 2>/dev/null | grep -c "ok installed") -eq 0 ]; then return 1; else return 0; fi; +} + +function install_requred_packages(){ + apt update &>> $script_log_file; + + requred_packages=("curl" "git-all" "ufw" "nginx"); + local package; + for package in ${requred_packages[@]}; do + if ! is_package_installed $package; then + # Kill apache process, because Debian configuring nginx package right during installation + if [ $package = "nginx" ]; then systemctl stop apache2; fi; + apt install --yes --force-yes -o DPkg::Options::="--force-confold" $package &>> $script_log_file; + if ! is_package_installed $package; then + echo_log_err_and_exit "Error: cannot install \"$package\" package"; + fi; + fi; + done; + + echo -e "\nAll required packages installed successfully"; +} + +function install_node(){ + curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash; + . ~/.nvm/nvm.sh; + . ~/.profile; + . ~/.bashrc; + nvm install 14.21.3; +} + +function install_relayer_repo(){ + git clone $relayer_soft_git_repo -b v6 $relayer_folder +} + +function install_docker_utilities(){ + local kernel_name=$(uname -s); + local processor_type=$(uname -m); + + curl -SL https://github.com/docker/compose/releases/download/v2.16.0/docker-compose-$kernel_name-$processor_type -o /usr/local/bin/docker-compose; + chmod +x /usr/local/bin/docker-compose; + + curl -s https://get.docker.com | bash; +} + +function configure_firewall(){ + ufw allow https/tcp; + ufw allow http/tcp; + ufw insert 1 allow OpenSSH; + echo "y" | ufw enable; +} + +function configure_nginx_reverse_proxy(){ + systemctl stop apache2; + + cp $relayer_folder/tornado.conf /etc/nginx/sites-available/default; + echo "stream { map_hash_bucket_size 128; map_hash_max_size 128; include /etc/nginx/conf.d/streams/*.conf; }" >> /etc/nginx/nginx.conf; + mkdir /etc/nginx/conf.d/streams; + cp $relayer_folder/tornado-stream.conf /etc/nginx/conf.d/streams/tornado-stream.conf; + + systemctl restart nginx; + systemctl stop nginx; +} + +function build_relayer_docker_container(){ + cd $relayer_folder && npm run build:docker; +} + +function prepare_environments(){ + tee $relayer_folder/.env.bsc $relayer_folder/.env.arb $relayer_folder/.env.goerli $relayer_folder/.env.eth $relayer_folder/.env.polygon $relayer_folder/.env.op \ + $relayer_folder/.env.avax $relayer_folder/.env.gnosis < $relayer_folder/.env.example > /dev/null; +} + +function main(){ + install_requred_packages; + install_node; + install_relayer_repo; + configure_firewall; + configure_nginx_reverse_proxy; + install_docker_utilities; + build_relayer_docker_container; + prepare_environments; + cd $relayer_folder; +} + +main; \ No newline at end of file diff --git a/package.json b/package.json index f4d0578..b9cb0e9 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,9 @@ "dev:server": "nodemon --watch './src/**/*.ts' --exec ts-node src/app/index.ts", "dev:healthWorker": "nodemon --watch './src/**/*.ts' --exec ts-node src/healthWorker.ts", "dev:txWorker": "nodemon --watch './src/**/*.ts' --exec ts-node src/txWorker.ts", - "build": "yarn build:abi && tsc", + "build": "tsc", "build:abi": "yarn typechain --target ethers-v5 --out-dir src/contracts ./abis/*.abi.json", + "build:docker": "docker build -t tornadocash/relayer:v6 .", "test": "tap --node-arg=--require=ts-node/register --no-check-coverage", "eslint": "eslint --ext .ts --ignore-path .gitignore .", "prettier:check": "npx prettier --check . --config .prettierrc --ignore-path .gitignore", diff --git a/src/config.ts b/src/config.ts index 263f161..d8ad411 100644 --- a/src/config.ts +++ b/src/config.ts @@ -12,7 +12,7 @@ export const redisUrl = process.env.REDIS_URL || 'redis://127.0.0.1:6379'; export const rpcUrl = process.env.HTTP_RPC_URL; export const CONFIRMATIONS = Number(process.env.CONFIRMATIONS ?? 4); export const MAX_GAS_PRICE = Number(process.env.MAX_GAS_PRICE ?? 1000); -export const BASE_FEE_RESERVE_PERCENTAGE = Number(process.env.BASE_FEE_RESERVE_PERCENTAGE ?? 25); +export const GAS_BUMP_PERCENTAGE = Number(process.env.GAS_BUMP_PERCENTAGE ?? 5); export const mainnetRpcUrl = process.env.MAINNET_RPC_URL || process.env.ORACLE_RPC_URL || 'https://api.securerpc.com/v1'; export const oracleRpcUrl = process.env.ORACLE_RPC_URL || 'https://api.securerpc.com/v1'; export const offchainOracleAddress = '0x07D91f5fb9Bf7798734C3f606dB065549F6893bb'; @@ -22,7 +22,7 @@ export const instances = tornConfig.instances; export const torn = tornConfig; export const port = Number(process.env.APP_PORT) || 8000; export const host = isProduction ? 'https://' + process.env.VIRTUAL_HOST : `http://localhost:${port}`; -export const tornadoServiceFee = Number(process.env.REGULAR_TORNADO_WITHDRAW_FEE); +export const tornadoServiceFee = Number(process.env.RELAYER_FEE); export const rewardAccount = process.env.REWARD_ACCOUNT; export const tornadoGoerliProxy = '0x454d870a72e29d5E5697f635128D18077BD04C60'; export const ovmGasPriceOracleContract = '0x420000000000000000000000000000000000000F'; @@ -48,7 +48,6 @@ export const minimumBalance = BigNumber.from(minimumBalances[netId] * 10) // BN .mul(decimals.div(10)) .toString(); export const minimumTornBalance = BigNumber.from(500).mul(decimals).toString(); -export const baseFeeReserve = Number(process.env.BASE_FEE_RESERVE_PERCENTAGE); export const tornToken = { tokenAddress: '0x77777FeDdddFfC19Ff86DB637967013e6C6A116C', symbol: 'TORN', diff --git a/src/contracts/OvmGasPriceOracleABI.ts b/src/contracts/OvmGasPriceOracleAbi.ts similarity index 100% rename from src/contracts/OvmGasPriceOracleABI.ts rename to src/contracts/OvmGasPriceOracleAbi.ts diff --git a/src/contracts/ProxyLightABI.ts b/src/contracts/ProxyLightAbi.ts similarity index 100% rename from src/contracts/ProxyLightABI.ts rename to src/contracts/ProxyLightAbi.ts diff --git a/src/contracts/TornadoProxyABI.ts b/src/contracts/TornadoProxyAbi.ts similarity index 100% rename from src/contracts/TornadoProxyABI.ts rename to src/contracts/TornadoProxyAbi.ts diff --git a/src/contracts/factories/OvmGasPriceOracleABI__factory.ts b/src/contracts/factories/OvmGasPriceOracleAbi__factory.ts similarity index 100% rename from src/contracts/factories/OvmGasPriceOracleABI__factory.ts rename to src/contracts/factories/OvmGasPriceOracleAbi__factory.ts diff --git a/src/contracts/factories/ProxyLightABI__factory.ts b/src/contracts/factories/ProxyLightAbi__factory.ts similarity index 100% rename from src/contracts/factories/ProxyLightABI__factory.ts rename to src/contracts/factories/ProxyLightAbi__factory.ts diff --git a/src/contracts/factories/TornadoProxyABI__factory.ts b/src/contracts/factories/TornadoProxyAbi__factory.ts similarity index 100% rename from src/contracts/factories/TornadoProxyABI__factory.ts rename to src/contracts/factories/TornadoProxyAbi__factory.ts diff --git a/src/services/tx.service.ts b/src/services/tx.service.ts index a8cda3b..b4fab5f 100644 --- a/src/services/tx.service.ts +++ b/src/services/tx.service.ts @@ -5,7 +5,7 @@ import { serialize } from '@ethersproject/transactions'; import { formatEther, parseUnits } from 'ethers/lib/utils'; import { BigNumber, BigNumberish, BytesLike } from 'ethers'; import { ProxyLightAbi, TornadoProxyAbi } from '../contracts'; -import { BASE_FEE_RESERVE_PERCENTAGE, CONFIRMATIONS, gasLimits, MAX_GAS_PRICE, netId, tornadoServiceFee } from '../config'; +import { GAS_BUMP_PERCENTAGE, CONFIRMATIONS, gasLimits, MAX_GAS_PRICE, netId, tornadoServiceFee } from '../config'; import { ChainIds, JobStatus, RelayerJobType } from '../types'; import { PriceService } from './price.service'; import { Job } from 'bullmq'; @@ -58,7 +58,7 @@ export class TxService { this.txManager = new TxManager({ privateKey, rpcUrl, - config: { THROW_ON_REVERT: true, CONFIRMATIONS, MAX_GAS_PRICE, BASE_FEE_RESERVE_PERCENTAGE }, + config: { THROW_ON_REVERT: true, CONFIRMATIONS, MAX_GAS_PRICE, GAS_BUMP_PERCENTAGE }, gasPriceOracleConfig, provider: this.provider, }); diff --git a/tornado-stream.conf b/tornado-stream.conf new file mode 100644 index 0000000..819debe --- /dev/null +++ b/tornado-stream.conf @@ -0,0 +1,15 @@ +map $ssl_preread_server_name $name { + yourdomain.com tornado_mainnet; + + default tornado_mainnet; +} + +upstream tornado_mainnet { + server 127.0.0.1:4380; +} + +server { + listen 0.0.0.0:443; + proxy_pass $name; + ssl_preread on; +} \ No newline at end of file diff --git a/tornado.conf b/tornado.conf new file mode 100644 index 0000000..efe418d --- /dev/null +++ b/tornado.conf @@ -0,0 +1,87 @@ +# If we receive X-Forwarded-Proto, pass it through; otherwise, pass along the +# scheme used to connect to this server +map $http_x_forwarded_proto $proxy_x_forwarded_proto { + default $http_x_forwarded_proto; + '' $scheme; +} +# If we receive X-Forwarded-Port, pass it through; otherwise, pass along the +# server port the client connected to +map $http_x_forwarded_port $proxy_x_forwarded_port { + default $http_x_forwarded_port; + '' $server_port; +} +# If we receive Upgrade, set Connection to "upgrade"; otherwise, delete any +# Connection header that may have been passed to this server +map $http_upgrade $proxy_connection { + default upgrade; + '' close; +} +# Apply fix for very long server names +server_names_hash_bucket_size 128; +# Default dhparam +# Set appropriate X-Forwarded-Ssl header based on $proxy_x_forwarded_proto +map $proxy_x_forwarded_proto $proxy_x_forwarded_ssl { + default off; + https on; +} +gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; +log_format vhost '$host $remote_addr - $remote_user [$time_local] ' + '"$request" $status $body_bytes_sent ' + '"$http_referer" "$http_user_agent" ' + '"$upstream_addr"'; +# HTTP 1.1 support +proxy_http_version 1.1; +proxy_buffering off; +proxy_set_header Host $http_host; +proxy_set_header Upgrade $http_upgrade; +proxy_set_header Connection $proxy_connection; +proxy_set_header X-Real-IP $remote_addr; +proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto; +proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl; +proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port; +proxy_set_header X-Original-URI $request_uri; +# Mitigate httpoxy attack (see README for details) +proxy_set_header Proxy ""; + +# Request rate limiting per second, 2Mb zone @ 5 requests per second +limit_req_zone $binary_remote_addr zone=one:2m rate=5r/s; +# Connections per IP limited to 2 +limit_conn_zone $binary_remote_addr zone=two:2m; + +server { + server_name _; # This is just an invalid value which will never trigger on a real hostname. + server_tokens off; + listen 80; + access_log /var/log/nginx/access.log vhost; + return 503; +} + +server { + server_name yourdomain.com; + + # Connection timeouts + client_body_timeout 10s; + client_header_timeout 10s; + + listen 80; + access_log /var/log/nginx/access.log vhost; + + # Do not HTTPS redirect LetsEncrypt ACME challenge + location ^~ /.well-known/acme-challenge/ { + limit_req zone=one; + limit_conn two 1; + + proxy_pass http://127.0.0.1:8000; + + break; + } + + location / { + limit_req zone=one; + limit_conn two 1; + + return 301 https://$host$request_uri; + } + +} \ No newline at end of file