diff --git a/build.gradle b/build.gradle
index d07b2ed1..edc148d9 100644
--- a/build.gradle
+++ b/build.gradle
@@ -64,7 +64,6 @@ configure(subprojects) {
junitVersion = '4.12'
jupiterVersion = '5.7.0'
kotlinVersion = '1.3.41'
- knowmXchangeVersion = '5.0.13'
langVersion = '3.11'
logbackVersion = '1.1.11'
loggingVersion = '1.2'
@@ -77,7 +76,6 @@ configure(subprojects) {
qrgenVersion = '1.3'
slf4jVersion = '1.7.30'
sparkVersion = '2.5.2'
- springBootVersion = '2.5.6'
os = osdetector.os == 'osx' ? 'mac' : osdetector.os == 'windows' ? 'win' : osdetector.os
}
@@ -115,7 +113,6 @@ configure([project(':cli'),
project(':relay'),
project(':seednode'),
project(':statsnode'),
- project(':pricenode'),
project(':inventory'),
project(':apitest')]) {
@@ -678,81 +675,6 @@ configure(project(':monitor')) {
}
-configure(project(':pricenode')) {
- apply plugin: "org.springframework.boot"
-
- apply plugin: 'io.spring.dependency-management'
-
- mainClassName = 'bisq.price.Main'
-
- version = file("src/main/resources/version.txt").text.trim()
-
- jar.manifest.attributes(
- "Implementation-Title": project.name,
- "Implementation-Version": version)
-
- ext['log4j2.version'] = '2.17.0'
-
- dependencies {
- implementation project(":common")
- implementation project(":core")
- annotationProcessor "org.projectlombok:lombok:$lombokVersion"
- compileOnly "org.projectlombok:lombok:$lombokVersion"
- implementation "com.google.code.gson:gson:$gsonVersion"
- implementation "com.google.guava:guava:$guavaVersion"
- implementation "commons-codec:commons-codec:$codecVersion"
- implementation "org.apache.httpcomponents:httpcore:$httpcoreVersion"
- implementation("org.apache.httpcomponents:httpclient:$httpclientVersion") {
- exclude(module: 'commons-codec')
- }
- implementation("org.knowm.xchange:xchange-binance:$knowmXchangeVersion")
- implementation("org.knowm.xchange:xchange-bitbay:$knowmXchangeVersion")
- implementation("org.knowm.xchange:xchange-bitfinex:$knowmXchangeVersion")
- implementation("org.knowm.xchange:xchange-bitflyer:$knowmXchangeVersion")
- implementation("org.knowm.xchange:xchange-bitstamp:$knowmXchangeVersion")
- implementation("org.knowm.xchange:xchange-btcmarkets:$knowmXchangeVersion")
- implementation("org.knowm.xchange:xchange-cexio:$knowmXchangeVersion")
- implementation("org.knowm.xchange:xchange-coinbasepro:$knowmXchangeVersion")
- implementation("org.knowm.xchange:xchange-coinmarketcap:$knowmXchangeVersion")
- implementation("org.knowm.xchange:xchange-coinmate:$knowmXchangeVersion")
- implementation("org.knowm.xchange:xchange-coinone:$knowmXchangeVersion")
- implementation("org.knowm.xchange:xchange-exmo:$knowmXchangeVersion")
- implementation("org.knowm.xchange:xchange-hitbtc:$knowmXchangeVersion")
- implementation("org.knowm.xchange:xchange-huobi:$knowmXchangeVersion")
- implementation("org.knowm.xchange:xchange-independentreserve:$knowmXchangeVersion")
- implementation("org.knowm.xchange:xchange-kraken:$knowmXchangeVersion")
- implementation("org.knowm.xchange:xchange-luno:$knowmXchangeVersion")
- implementation("org.knowm.xchange:xchange-mercadobitcoin:$knowmXchangeVersion")
- implementation("org.knowm.xchange:xchange-paribu:$knowmXchangeVersion")
- implementation("org.knowm.xchange:xchange-poloniex:$knowmXchangeVersion")
- implementation("org.knowm.xchange:xchange-quoine:$knowmXchangeVersion")
- implementation("org.springframework.boot:spring-boot-starter-web:$springBootVersion")
- testAnnotationProcessor "org.projectlombok:lombok:$lombokVersion"
- testCompileOnly "org.projectlombok:lombok:$lombokVersion"
- testImplementation "org.junit.jupiter:junit-jupiter-api:$jupiterVersion"
- testImplementation "org.junit.jupiter:junit-jupiter-params:$jupiterVersion"
- testImplementation "org.mockito:mockito-core:$mockitoVersion"
- testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:$jupiterVersion")
- }
-
- test {
- useJUnitPlatform()
-
- // Disabled by default, since spot provider tests include connections to external API endpoints
- // Can be enabled by adding -Dtest.pricenode.includeSpotProviderTests=true to the gradle command:
- // ./gradlew test -Dtest.pricenode.includeSpotProviderTests=true
- if (System.properties['test.pricenode.includeSpotProviderTests'] != 'true') {
- project.logger.lifecycle('Pricenode: Skipping spot provider tests')
- exclude 'bisq/price/spot/providers/**'
- }
- }
-
- task stage {
- dependsOn assemble
- }
-}
-
-
configure(project(':relay')) {
mainClassName = 'bisq.relay.RelayMain'
diff --git a/pricenode/Procfile b/pricenode/Procfile
deleted file mode 100644
index 00c7115e..00000000
--- a/pricenode/Procfile
+++ /dev/null
@@ -1 +0,0 @@
-web: if [ "$HIDDEN" == true ]; then ./tor/bin/run_tor java -jar -Dserver.port=$PORT build/libs/haveno-pricenode.jar; else java -jar -Dserver.port=$PORT build/libs/haveno-pricenode.jar; fi
diff --git a/pricenode/README-HEROKU.md b/pricenode/README-HEROKU.md
deleted file mode 100644
index ab6081cd..00000000
--- a/pricenode/README-HEROKU.md
+++ /dev/null
@@ -1,42 +0,0 @@
-Deploy on Heroku
---------
-
-Run the following commands:
-
- heroku create
- heroku buildpacks:add heroku/gradle
- git push heroku master
- curl https://your-app-123456.herokuapp.com/getAllMarketPrices
-
-To register the node as a Tor hidden service, first install the Heroku Tor buildpack:
-
- heroku buildpacks:add https://github.com/cbeams/heroku-buildpack-tor.git
- git push heroku master
-
-> NOTE: this deployment will take a while, because the new buildpack must download and build Tor from source.
-
-Next, generate your Tor hidden service private key and .onion address:
-
- heroku run bash
- ./tor/bin/tor -f torrc
-
-When the process reports that it is "100% bootstrapped", kill it, then copy the generated private key and .onion hostname values:
-
- cat build/tor-hidden-service/hostname
- cat build/tor-hidden-service/private_key
- exit
-
-> IMPORTANT: Save the private key value in a secure location so that this node can be re-created elsewhere with the same .onion address in the future if necessary.
-
-Now configure the hostname and private key values as environment variables for your Heroku app:
-
- heroku config:set HIDDEN=true HIDDEN_DOT_ONION=[your .onion] HIDDEN_PRIVATE_KEY="[your tor privkey]"
- git push heroku master
-
-When the application finishes restarting, you should still be able to access it via the clearnet, e.g. with:
-
- curl https://your-app-123456.herokuapp.com/getAllMarketPrices
-
-And via your Tor Browser at:
-
- http://$YOUR_ONION/getAllMarketPrices
diff --git a/pricenode/README.md b/pricenode/README.md
deleted file mode 100644
index 8b366432..00000000
--- a/pricenode/README.md
+++ /dev/null
@@ -1,84 +0,0 @@
-# Haveno-pricenode
-
-## Overview
-
-The Haveno pricenode is a simple HTTP service that fetches, transforms and relays data from third-party price providers to Haveno exchange clients on request. Available prices include:
-
- - Bitcoin exchange rates, available at `/getAllMarketPrices`, and
- - Bitcoin mining fee rates, available at `/getFees`
-
-Pricenodes are deployed in production as Tor hidden services. This is not because the location of these nodes needs to be kept secret, but rather so that Haveno exchange clients do not need to exit the Tor network in order to get price data.
-
-Anyone can run a pricenode, but it must be _discoverable_ in order for it to do any good. For exchange clients to discover your pricenode, its .onion address must be hard-coded in the Haveno exchange client's `ProvidersRepository` class. Alternatively, users can point explicitly to given pricenode (or set of pricenodes) with the exchange client's `--providers` command line option.
-
-Pricenodes can be deployed anywhere Java and Tor binaries can be run. Instructions below cover deployment on localhost, and instructions [how to deploy on Heroku](README-HEROKU.md) are also available.
-
-Pricenodes should be cheap to run with regard to both time and money. The application itself is non-resource intensive and can be run on the low-end of most providers' paid tiers.
-
-A pricenode operator's main responsibilities are to ensure their node(s) are available and up-to-date. Releases are currently source-only, with the assumption that most operators will favor Git-based "push to deploy" workflows.
-
-## Prerequisites for running a pricenode
-
-To run a pricenode, you will need:
-
- - JDK 8 if you want to build and run a node locally.
- - The `tor` binary (e.g. `brew install tor`) if you want to run a hidden service locally.
-
-## How to deploy for production
-
-### Install
-
-Run the one-command installer:
-
-```bash
-curl -s https://raw.githubusercontent.com/haveno-dex/haveno/master/pricenode/install_pricenode_debian.sh | sudo bash
-```
-
-This will install the pricenode under the user `pricenode`. At the end of the installer script, it should print your Tor onion hostname.
-
-### Test
-
-To manually test endpoints, run each of the following:
-
-``` bash
-curl http://localhost:8078/getAllMarketPrices
-curl http://localhost:8078/getFees
-curl http://localhost:8078/getParams
-curl http://localhost:8078/info
-```
-
-### Monitoring
-
-If you run a main pricenode, you also are obliged to activate the monitoring feed by running
-
-```bash
-bash <(curl -s https://raw.githubusercontent.com/haveno-dex/haveno/master/monitor/install_collectd_debian.sh)
-```
-
-Furthermore, you are obliged to provide network size data to the monitor by running
-
-```bash
-curl -s https://raw.githubusercontent.com/haveno-dex/Haveno/master/pricenode/install_networksize_debian.sh | sudo bash
-```
-
-### Updating
-
-Update your Haveno code in /Haveno with ```git pull```
-
-Then build an updated pricenode:
-
-```./gradlew :pricenode:installDist -x test```
-
-## How to deploy elsewhere
-
- - [README-HEROKU.md](README-HEROKU.md)
- - [docker/README.md](docker/README.md)
-
-
-## Bitcoin mining fee estimates
-
-The pricenode exposes a service API to Haveno clients under `/getFees`.
-
-This API returns a mining fee rate estimate, representing an average of several mining fee rate values retrieved from different `mempool.space` instances.
-
-To configure which `mempool.space` instances are queried to calculate this average, see the relevant section in the file `application.properties`.
diff --git a/pricenode/collectd.conf.snippet b/pricenode/collectd.conf.snippet
deleted file mode 100644
index 49d93c5e..00000000
--- a/pricenode/collectd.conf.snippet
+++ /dev/null
@@ -1,5 +0,0 @@
-LoadPlugin exec
-
-
- Exec "__USER_GROUP__" "__SCRAPERSCRIPT__"
-
diff --git a/pricenode/docker/Dockerfile b/pricenode/docker/Dockerfile
deleted file mode 100644
index 75401bee..00000000
--- a/pricenode/docker/Dockerfile
+++ /dev/null
@@ -1,33 +0,0 @@
-###
-# Haveno pricenode dockerfile
-###
-
-# pull base image
-FROM openjdk:11-jdk
-
-# install tor
-RUN apt-get update && apt-get install -y --no-install-recommends \
- tor && rm -rf /var/lib/apt/lists/*
-
-# copy tor configuration file
-COPY torrc /etc/tor/
-# give proper permissions for tor configuration file
-RUN chown debian-tor:debian-tor /etc/tor/torrc
-# add haveno user
-RUN useradd -d /haveno -G debian-tor haveno
-# make haveno directory
-RUN mkdir -p /haveno
-# give haveno user proper permissions
-RUN chown haveno:haveno /haveno
-# clone haveno repository
-RUN git clone https://github.com/haveno-dex/haveno.git /haveno/haveno
-# build pricenode
-WORKDIR /haveno/haveno
-RUN ./gradlew :pricenode:installDist -x test
-# set proper java options
-ENV JAVA_OPTS=""
-# expose ports
-EXPOSE 80
-EXPOSE 8078
-# set launch command (tor and pricenode)
-CMD tor && /haveno/haveno/haveno-pricenode 2
diff --git a/pricenode/docker/README.md b/pricenode/docker/README.md
deleted file mode 100644
index 34fdafd3..00000000
--- a/pricenode/docker/README.md
+++ /dev/null
@@ -1,26 +0,0 @@
-Needed software to start a pricenode
-==
-
-* docker
-* docker-compose
-
-How to start
-==
-
-`docker compose up -d`
-
-
-How to monitor
-==
-
-See if it's running: `docker ps`
-
-Check the logs: `docker-compose logs`
-
-Check the tor hostname: `docker exec docker_pricenode_1 cat /var/lib/tor/pricenode/hostname`
-
-
-How to test
-==
-
-Refer to the main pricenode [README](../README.md).
\ No newline at end of file
diff --git a/pricenode/docker/docker-compose.yml b/pricenode/docker/docker-compose.yml
deleted file mode 100644
index 65815f6c..00000000
--- a/pricenode/docker/docker-compose.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-version: '3'
-
-services:
- pricenode:
- restart: unless-stopped
- build:
- context: .
- ports:
- - 80:80
- - 8078:8078
diff --git a/pricenode/docker/torrc b/pricenode/docker/torrc
deleted file mode 100644
index 4c39cdb6..00000000
--- a/pricenode/docker/torrc
+++ /dev/null
@@ -1,4 +0,0 @@
-HiddenServiceDir /var/lib/tor/pricenode/
-HiddenServicePort 80 127.0.0.1:8078
-HiddenServiceVersion 3
-RunAsDaemon 1
diff --git a/pricenode/haveno-pricenode.env b/pricenode/haveno-pricenode.env
deleted file mode 100644
index f77a6675..00000000
--- a/pricenode/haveno-pricenode.env
+++ /dev/null
@@ -1 +0,0 @@
-JAVA_OPTS="-XX:+ExitOnOutOfMemoryError"
diff --git a/pricenode/haveno-pricenode.service b/pricenode/haveno-pricenode.service
deleted file mode 100644
index 6aa1a1b8..00000000
--- a/pricenode/haveno-pricenode.service
+++ /dev/null
@@ -1,25 +0,0 @@
-[Unit]
-Description=Haveno Price Node
-After=network.target
-
-[Service]
-SyslogIdentifier=Haveno-pricenode
-EnvironmentFile=/etc/default/haveno-pricenode.env
-ExecStart=/pricenode/haveno/haveno-pricenode 2
-ExecStop=/bin/kill -TERM ${MAINPID}
-Restart=on-failure
-
-User=pricenode
-Group=pricenode
-
-PrivateTmp=true
-ProtectSystem=full
-NoNewPrivileges=true
-PrivateDevices=true
-MemoryDenyWriteExecute=false
-ProtectControlGroups=true
-ProtectKernelTunables=true
-RestrictSUIDSGID=true
-
-[Install]
-WantedBy=multi-user.target
diff --git a/pricenode/install_hsversion_debian.sh b/pricenode/install_hsversion_debian.sh
deleted file mode 100755
index 631a0278..00000000
--- a/pricenode/install_hsversion_debian.sh
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/bin/sh
-set -e
-
-echo "[*] Network Size Monitoring installation script"
-
-##### change paths if necessary for your system
-
-ROOT_USER=root
-
-SCRAPER_HOME=/journalreader
-SCRAPER_USER=journalreader
-SCRAPER_GROUP=systemd-journal
-
-#####
-echo "[*] Checking environment..."
-if [ ! -f "/etc/collectd/collectd.conf" ]; then
- echo 'Collectd is not installed. Did you do the install_monitoring_debian.sh?'
- echo 'Exiting...'
- exit
-fi
-if ! grep -q "journalreader" /etc/passwd; then
- echo 'User not found. Did you run the install_networksize_debian.sh?'
- echo 'Exiting...'
- exit
-fi
-
-echo "[*] Installing journal parser script"
-curl -s https://raw.githubusercontent.com/bisq-network/bisq/master/pricenode/journalscraper_hsversion.sh > /tmp/journalscraper_hsversion.sh
-sudo -H -i -u "${ROOT_USER}" install -c -o "${SCRAPER_USER}" -g "${SCRAPER_GROUP}" -m 744 /tmp/journalscraper_hsversion.sh "${SCRAPER_HOME}/scraperscript_hsversion.sh"
-
-echo "[*] Installing collectd config"
-curl -s https://raw.githubusercontent.com/bisq-network/bisq/master/pricenode/collectd.conf.snippet > /tmp/collectd.conf.snippet
-sudo -H -i -u "${ROOT_USER}" sed -i -e "s/LoadPlugin exec//" /tmp/collectd.conf.snippet
-sudo -H -i -u "${ROOT_USER}" /bin/sh -c "cat /tmp/collectd.conf.snippet >> /etc/collectd/collectd.conf"
-sudo -H -i -u "${ROOT_USER}" sed -i -e "s/__USER_GROUP__/${SCRAPER_USER}:${SCRAPER_GROUP}/" /etc/collectd/collectd.conf
-sudo -H -i -u "${ROOT_USER}" sed -i -e "s!__SCRAPERSCRIPT__!${SCRAPER_HOME}/scraperscript_hsversion.sh!" /etc/collectd/collectd.conf
-
-echo "[*] Restarting services"
-sudo -H -i -u "${ROOT_USER}" systemctl restart collectd.service
-
-echo '[*] Done!'
diff --git a/pricenode/install_networksize_debian.sh b/pricenode/install_networksize_debian.sh
deleted file mode 100755
index bc25b3c6..00000000
--- a/pricenode/install_networksize_debian.sh
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/bin/sh
-set -e
-
-echo "[*] Network Size Monitoring installation script"
-
-##### change paths if necessary for your system
-
-ROOT_USER=root
-
-SCRAPER_HOME=/journalreader
-SCRAPER_USER=journalreader
-SCRAPER_GROUP=systemd-journal
-
-#####
-echo "[*] Checking environment..."
-if [ ! -f "/etc/collectd/collectd.conf" ]; then
- echo 'Collectd is not installed. Did you do the install_monitoring_debian.sh?'
- echo 'Exiting...'
- exit
-fi
-
-echo "[*] Creating journal reader user"
-sudo -H -i -u "${ROOT_USER}" useradd -d "${SCRAPER_HOME}" -G "${SCRAPER_GROUP}" "${SCRAPER_USER}"
-sudo -H -i -u "${ROOT_USER}" mkdir -p "${SCRAPER_HOME}"
-sudo -H -i -u "${ROOT_USER}" chown "${SCRAPER_USER}":"${SCRAPER_GROUP}" ${SCRAPER_HOME}
-
-echo "[*] Installing journal parser script"
-curl -s https://raw.githubusercontent.com/bisq-network/bisq/master/pricenode/journalscraper.sh > /tmp/journalscraper.sh
-sudo -H -i -u "${ROOT_USER}" install -c -o "${SCRAPER_USER}" -g "${SCRAPER_GROUP}" -m 744 /tmp/journalscraper.sh "${SCRAPER_HOME}/scraperscript.sh"
-
-echo "[*] Installing collectd config"
-curl -s https://raw.githubusercontent.com/bisq-network/bisq/master/pricenode/collectd.conf.snippet > /tmp/collectd.conf.snippet
-sudo -H -i -u "${ROOT_USER}" /bin/sh -c "cat /tmp/collectd.conf.snippet >> /etc/collectd/collectd.conf"
-sudo -H -i -u "${ROOT_USER}" sed -i -e "s/__USER_GROUP__/${SCRAPER_USER}:${SCRAPER_GROUP}/" /etc/collectd/collectd.conf
-sudo -H -i -u "${ROOT_USER}" sed -i -e "s!__SCRAPERSCRIPT__!${SCRAPER_HOME}/scraperscript.sh!" /etc/collectd/collectd.conf
-
-sudo -H -i -u "${ROOT_USER}" systemctl enable collectd.service
-
-echo "[*] Restarting services"
-sudo -H -i -u "${ROOT_USER}" systemctl restart collectd.service
-
-echo '[*] Done!'
diff --git a/pricenode/install_pricenode_debian.sh b/pricenode/install_pricenode_debian.sh
deleted file mode 100755
index 311d9727..00000000
--- a/pricenode/install_pricenode_debian.sh
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/usr/bin/env bash
-set -e
-
-echo "[*] haveno-pricenode installation script"
-
-##### change as necessary for your system
-
-SYSTEMD_SERVICE_HOME=/etc/systemd/system
-SYSTEMD_ENV_HOME=/etc/default
-
-ROOT_USER=root
-ROOT_GROUP=root
-#ROOT_HOME=/root
-
-HAVENO_USER=pricenode
-HAVENO_GROUP=pricenode
-HAVENO_HOME=/pricenode
-
-HAVENO_REPO_URL=https://github.com/haveno-dex/haveno
-HAVENO_REPO_NAME=haveno
-HAVENO_REPO_TAG=master
-HAVENO_LATEST_RELEASE=master
-HAVENO_TORHS=pricenode
-
-TOR_PKG="tor"
-#TOR_USER=debian-tor
-TOR_GROUP=debian-tor
-TOR_CONF=/etc/tor/torrc
-TOR_RESOURCES=/var/lib/tor
-
-#####
-
-echo "[*] Upgrading apt packages"
-sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get update -q
-sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get upgrade -qq -y
-
-echo "[*] Installing Tor"
-sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get install -qq -y "${TOR_PKG}"
-
-echo "[*] Adding Tor configuration"
-if ! grep "${HAVENO_TORHS}" /etc/tor/torrc >/dev/null 2>&1;then
- sudo -H -i -u "${ROOT_USER}" sh -c "echo HiddenServiceDir ${TOR_RESOURCES}/${HAVENO_TORHS}/ >> ${TOR_CONF}"
- sudo -H -i -u "${ROOT_USER}" sh -c "echo HiddenServicePort 80 127.0.0.1:8078 >> ${TOR_CONF}"
- sudo -H -i -u "${ROOT_USER}" sh -c "echo HiddenServiceVersion 3 >> ${TOR_CONF}"
-fi
-
-echo "[*] Creating Haveno user with Tor access"
-sudo -H -i -u "${ROOT_USER}" useradd -d "${HAVENO_HOME}" -G "${TOR_GROUP}" "${HAVENO_USER}"
-
-echo "[*] Creating Haveno homedir"
-sudo -H -i -u "${ROOT_USER}" mkdir -p "${HAVENO_HOME}"
-sudo -H -i -u "${ROOT_USER}" chown "${HAVENO_USER}":"${HAVENO_GROUP}" ${HAVENO_HOME}
-
-echo "[*] Cloning Haveno repo"
-sudo -H -i -u "${HAVENO_USER}" git config --global advice.detachedHead false
-sudo -H -i -u "${HAVENO_USER}" git clone --branch "${HAVENO_REPO_TAG}" "${HAVENO_REPO_URL}" "${HAVENO_HOME}/${HAVENO_REPO_NAME}"
-
-echo "[*] Installing OpenJDK 11"
-sudo -H -i -u "${ROOT_USER}" apt-get install -qq -y openjdk-11-jdk
-
-echo "[*] Checking out Haveno ${HAVENO_LATEST_RELEASE}"
-sudo -H -i -u "${HAVENO_USER}" sh -c "cd ${HAVENO_HOME}/${HAVENO_REPO_NAME} && git checkout ${HAVENO_LATEST_RELEASE}"
-
-echo "[*] Building Haveno from source"
-sudo -H -i -u "${HAVENO_USER}" sh -c "cd ${HAVENO_HOME}/${HAVENO_REPO_NAME} && ./gradlew :pricenode:installDist -x test < /dev/null" # redirect from /dev/null is necessary to workaround gradlew non-interactive shell hanging issue
-
-echo "[*] Installing haveno-pricenode systemd service"
-sudo -H -i -u "${ROOT_USER}" install -c -o "${ROOT_USER}" -g "${ROOT_GROUP}" -m 644 "${HAVENO_HOME}/${HAVENO_REPO_NAME}/pricenode/haveno-pricenode.service" "${SYSTEMD_SERVICE_HOME}"
-sudo -H -i -u "${ROOT_USER}" install -c -o "${ROOT_USER}" -g "${ROOT_GROUP}" -m 644 "${HAVENO_HOME}/${HAVENO_REPO_NAME}/pricenode/haveno-pricenode.env" "${SYSTEMD_ENV_HOME}"
-
-echo "[*] Reloading systemd daemon configuration"
-sudo -H -i -u "${ROOT_USER}" systemctl daemon-reload
-
-echo "[*] Enabling haveno-pricenode service"
-sudo -H -i -u "${ROOT_USER}" systemctl enable haveno-pricenode.service
-
-echo "[*] Starting haveno-pricenode service"
-sudo -H -i -u "${ROOT_USER}" systemctl start haveno-pricenode.service
-sleep 5
-sudo -H -i -u "${ROOT_USER}" journalctl --no-pager --unit haveno-pricenode
-
-echo "[*] Restarting Tor"
-sudo -H -i -u "${ROOT_USER}" service tor restart
-sleep 5
-
-echo '[*] Done!'
-echo -n '[*] Access your pricenode at http://'
-cat "${TOR_RESOURCES}/${HAVENO_TORHS}/hostname"
-
-exit 0
diff --git a/pricenode/journalscraper.sh b/pricenode/journalscraper.sh
deleted file mode 100755
index df80ddc3..00000000
--- a/pricenode/journalscraper.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-
-HOSTNAME="${COLLECTD_HOSTNAME:-localhost}"
-INTERVAL=750
-
-last=$(date +"%F %T" -d "$INTERVAL seconds ago")
-while true;
-do
- now=$(date +"%F %T")
-
- journalctl -u bisq-pricenode --since="$last" --until="$now" | grep -Eo "getAllMarketPrices.*bisq/[0-9].[0-9].[0-9]" | cut -d / -f 2 | sort | uniq -c | while read -r line; do
- number=$(echo "${line}" | cut -d ' ' -f 1);
- version=$(echo "${line}" | cut -d \ -f 2);
- version=${version//./_};
- echo "PUTVAL $HOSTNAME/requestsPer750Seconds/gauge-v$version interval=$INTERVAL N:$number";
- done
- last=$now
-
- sleep $INTERVAL
-done
diff --git a/pricenode/journalscraper_hsversion.sh b/pricenode/journalscraper_hsversion.sh
deleted file mode 100755
index f5d710b8..00000000
--- a/pricenode/journalscraper_hsversion.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-
-HOSTNAME="${COLLECTD_HOSTNAME:-localhost}"
-INTERVAL=750
-
-last=$(date +"%F %T" -d "$INTERVAL seconds ago")
-while true;
-do
- now=$(date +"%F %T")
-
- journalctl -u bisq-pricenode --since="$last" --until="$now" | grep -Eo "getAllMarketPrices.*HSv[0-9]" | grep -o "HSv[0-9]" | sort | uniq -c | while read -r line; do
- number=$(echo "${line}" | cut -d ' ' -f 1);
- version=$(echo "${line}" | cut -d \ -f 2);
- version=${version//./_};
- echo "PUTVAL $HOSTNAME/hsversionStats/gauge-$version interval=$INTERVAL N:$number";
- done
- last=$now
-
- sleep $INTERVAL
-done
diff --git a/pricenode/src/main/java/bisq/price/Main.java b/pricenode/src/main/java/bisq/price/Main.java
deleted file mode 100644
index 3e83fc49..00000000
--- a/pricenode/src/main/java/bisq/price/Main.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * This file is part of Haveno.
- *
- * Haveno is free software: you can redistribute it and/or modify it
- * under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at
- * your option) any later version.
- *
- * Haveno is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with Haveno. If not, see .
- */
-
-package bisq.price;
-
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.builder.SpringApplicationBuilder;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.UncheckedIOException;
-
-import java.util.Properties;
-
-@SpringBootApplication
-public class Main {
-
- public static void main(String[] args) {
- new SpringApplicationBuilder(Main.class)
- .properties(bisqProperties())
- .run(args);
- }
-
- private static Properties bisqProperties() {
- Properties props = new Properties();
- File propsFile = new File(System.getenv("HOME"), ".config/haveno.properties");
- if (propsFile.exists()) {
- try {
- props.load(new FileInputStream(propsFile));
- } catch (IOException ex) {
- throw new UncheckedIOException(ex);
- }
- }
- return props;
- }
-}
diff --git a/pricenode/src/main/java/bisq/price/PriceController.java b/pricenode/src/main/java/bisq/price/PriceController.java
deleted file mode 100644
index dbea4eba..00000000
--- a/pricenode/src/main/java/bisq/price/PriceController.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * This file is part of Haveno.
- *
- * Haveno is free software: you can redistribute it and/or modify it
- * under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at
- * your option) any later version.
- *
- * Haveno is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with Haveno. If not, see .
- */
-
-package bisq.price;
-
-import org.springframework.web.bind.annotation.ModelAttribute;
-
-import javax.servlet.http.HttpServletRequest;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public abstract class PriceController {
-
- protected final Logger log = LoggerFactory.getLogger(this.getClass());
-
- @ModelAttribute
- public void logRequest(HttpServletRequest request) {
- log.info("Incoming {} request from: {}", request.getServletPath(), request.getHeader("User-Agent"));
- }
-}
diff --git a/pricenode/src/main/java/bisq/price/PriceProvider.java b/pricenode/src/main/java/bisq/price/PriceProvider.java
deleted file mode 100644
index 20af8ef5..00000000
--- a/pricenode/src/main/java/bisq/price/PriceProvider.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * This file is part of Haveno.
- *
- * Haveno is free software: you can redistribute it and/or modify it
- * under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at
- * your option) any later version.
- *
- * Haveno is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with Haveno. If not, see .
- */
-
-package bisq.price;
-
-import bisq.common.UserThread;
-
-import org.springframework.context.SmartLifecycle;
-
-import java.time.Duration;
-
-import java.util.Timer;
-import java.util.TimerTask;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Supplier;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public abstract class PriceProvider implements SmartLifecycle, Supplier {
-
- protected final Logger log = LoggerFactory.getLogger(this.getClass());
-
- private final Timer timer = new Timer(true);
-
- protected final Duration refreshInterval;
-
- private T cachedResult;
-
- public PriceProvider(Duration refreshInterval) {
- this.refreshInterval = refreshInterval;
- log.info("will refresh every {}", refreshInterval);
- }
-
- @Override
- public final T get() {
- return cachedResult;
- }
-
- @Override
- public final void start() {
- // do the initial refresh asynchronously
- UserThread.runAfter(() -> {
- try {
- refresh();
- } catch (Throwable t) {
- log.warn("initial refresh failed", t);
- }
- }, 1, TimeUnit.MILLISECONDS);
-
- timer.scheduleAtFixedRate(new TimerTask() {
- @Override
- public void run() {
- try {
- refresh();
- } catch (Throwable t) {
- // we only log scheduled calls to refresh that fail to ensure that
- // the application does *not* halt, assuming the failure is temporary
- // and on the side of the upstream price provider, eg. BitcoinAverage
- log.warn("refresh failed", t);
- }
- }
- }, refreshInterval.toMillis(), refreshInterval.toMillis());
- }
-
- private void refresh() {
- try {
- long ts = System.currentTimeMillis();
- cachedResult = doGet();
- log.info("refresh took {} ms.", (System.currentTimeMillis() - ts));
- onRefresh();
- } catch (Exception e) {
- log.warn("Error refreshing price provider {}", getClass());
- }
- }
-
- protected abstract T doGet();
-
- protected void onRefresh() {
- }
-
- @Override
- public void stop() {
- timer.cancel();
- }
-
- @Override
- public void stop(Runnable callback) {
- stop();
- callback.run();
- }
-
- @Override
- public boolean isAutoStartup() {
- return true;
- }
-
- @Override
- public boolean isRunning() {
- return cachedResult != null;
- }
-
- @Override
- public int getPhase() {
- return 0;
- }
-}
diff --git a/pricenode/src/main/java/bisq/price/mining/FeeRate.java b/pricenode/src/main/java/bisq/price/mining/FeeRate.java
deleted file mode 100644
index 5c23576f..00000000
--- a/pricenode/src/main/java/bisq/price/mining/FeeRate.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * This file is part of Haveno.
- *
- * Haveno is free software: you can redistribute it and/or modify it
- * under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at
- * your option) any later version.
- *
- * Haveno is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with Haveno. If not, see .
- */
-
-package bisq.price.mining;
-
-/**
- * A value object representing the mining fee rate for a given base currency.
- */
-public class FeeRate {
-
- private final String currency;
- private final long price;
- private final long minimumFee;
- private final long timestamp;
-
- public FeeRate(String currency, long price, long minimumFee, long timestamp) {
- this.currency = currency;
- this.price = price;
- this.minimumFee = minimumFee;
- this.timestamp = timestamp;
- }
-
- public String getCurrency() {
- return currency;
- }
-
- public long getPrice() {
- return price;
- }
-
- public long getMinimumFee() {
- return minimumFee;
- }
-
- public long getTimestamp() {
- return timestamp;
- }
-}
diff --git a/pricenode/src/main/java/bisq/price/mining/FeeRateController.java b/pricenode/src/main/java/bisq/price/mining/FeeRateController.java
deleted file mode 100644
index 6b69cd17..00000000
--- a/pricenode/src/main/java/bisq/price/mining/FeeRateController.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * This file is part of Haveno.
- *
- * Haveno is free software: you can redistribute it and/or modify it
- * under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at
- * your option) any later version.
- *
- * Haveno is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with Haveno. If not, see .
- */
-
-package bisq.price.mining;
-
-import bisq.price.PriceController;
-
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.Map;
-
-@RestController
-class FeeRateController extends PriceController {
-
- private final FeeRateService feeRateService;
-
- public FeeRateController(FeeRateService feeRateService) {
- this.feeRateService = feeRateService;
- }
-
- @GetMapping(path = "/getFees")
- public Map getFees() {
- return feeRateService.getFees();
- }
-}
diff --git a/pricenode/src/main/java/bisq/price/mining/FeeRateProvider.java b/pricenode/src/main/java/bisq/price/mining/FeeRateProvider.java
deleted file mode 100644
index 62dabf3f..00000000
--- a/pricenode/src/main/java/bisq/price/mining/FeeRateProvider.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * This file is part of Haveno.
- *
- * Haveno is free software: you can redistribute it and/or modify it
- * under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at
- * your option) any later version.
- *
- * Haveno is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with Haveno. If not, see .
- */
-
-package bisq.price.mining;
-
-import bisq.price.PriceProvider;
-
-import java.time.Duration;
-
-/**
- * Abstract base class for providers of mining {@link FeeRate} data.
- */
-public abstract class FeeRateProvider extends PriceProvider {
-
- public static final long MIN_FEE_RATE_FOR_WITHDRAWAL = 2; // satoshi/vbyte
- public static final long MIN_FEE_RATE_FOR_TRADING = 10; // satoshi/vbyte
- public static final long MAX_FEE_RATE = 1000;
-
- public FeeRateProvider(Duration refreshInterval) {
- super(refreshInterval);
- }
-}
diff --git a/pricenode/src/main/java/bisq/price/mining/FeeRateService.java b/pricenode/src/main/java/bisq/price/mining/FeeRateService.java
deleted file mode 100644
index 509daacb..00000000
--- a/pricenode/src/main/java/bisq/price/mining/FeeRateService.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * This file is part of Haveno.
- *
- * Haveno is free software: you can redistribute it and/or modify it
- * under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at
- * your option) any later version.
- *
- * Haveno is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with Haveno. If not, see .
- */
-
-package bisq.price.mining;
-
-import bisq.common.config.Config;
-
-import org.springframework.stereotype.Service;
-
-import java.time.Instant;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * High-level mining {@link FeeRate} operations.
- */
-@Service
-public class FeeRateService {
-
- private final List providers;
- protected final Logger log = LoggerFactory.getLogger(this.getClass());
-
- /**
- * Construct a {@link FeeRateService} with a list of all {@link FeeRateProvider}
- * implementations discovered via classpath scanning.
- *
- * @param providers all {@link FeeRateProvider} implementations in ascending
- * order of precedence
- */
- public FeeRateService(List providers) {
- this.providers = providers;
- }
-
- public Map getFees() {
- Map metadata = new HashMap<>();
- Map allFeeRates = new HashMap<>();
-
- AtomicLong sumOfAllFeeRates = new AtomicLong();
- AtomicLong sumOfAllMinFeeRates = new AtomicLong();
- AtomicInteger amountOfFeeRates = new AtomicInteger();
-
- // Process each provider, retrieve and store their fee rate
- providers.forEach(p -> {
- FeeRate feeRate = p.get();
- if (feeRate == null) {
- log.warn("feeRate is null, provider={} ", p.toString());
- return;
- }
- String currency = feeRate.getCurrency();
- if ("BTC".equals(currency)) {
- sumOfAllFeeRates.getAndAdd(feeRate.getPrice());
- sumOfAllMinFeeRates.getAndAdd(feeRate.getMinimumFee());
- amountOfFeeRates.getAndAdd(1);
- }
- });
-
- // Calculate the average
- long averageFeeRate = (amountOfFeeRates.intValue() > 0)
- ? sumOfAllFeeRates.longValue() / amountOfFeeRates.intValue()
- : FeeRateProvider.MIN_FEE_RATE_FOR_TRADING;
- long averageMinFeeRate = (amountOfFeeRates.intValue() > 0)
- ? sumOfAllMinFeeRates.longValue() / amountOfFeeRates.intValue()
- : FeeRateProvider.MIN_FEE_RATE_FOR_WITHDRAWAL;
-
- // Make sure the returned value is within the min-max range
- averageFeeRate = Math.max(averageFeeRate, FeeRateProvider.MIN_FEE_RATE_FOR_TRADING);
- averageFeeRate = Math.min(averageFeeRate, FeeRateProvider.MAX_FEE_RATE);
- averageMinFeeRate = Math.max(averageMinFeeRate, FeeRateProvider.MIN_FEE_RATE_FOR_WITHDRAWAL);
- averageMinFeeRate = Math.min(averageMinFeeRate, FeeRateProvider.MAX_FEE_RATE);
-
- // Prepare response: Add timestamp of now
- // Since this is an average, the timestamp is associated with when the moment in
- // time when the avg was computed
- metadata.put(Config.BTC_FEES_TS, Instant.now().getEpochSecond());
-
- // Prepare response: Add the fee average
- allFeeRates.put(Config.BTC_TX_FEE, averageFeeRate);
- allFeeRates.put(Config.BTC_MIN_TX_FEE, averageMinFeeRate);
-
- // Build response
- return new HashMap<>() {{
- putAll(metadata);
- put(Config.LEGACY_FEE_DATAMAP, allFeeRates);
- }};
- }
-}
diff --git a/pricenode/src/main/java/bisq/price/mining/providers/MempoolFeeRateProvider.java b/pricenode/src/main/java/bisq/price/mining/providers/MempoolFeeRateProvider.java
deleted file mode 100644
index d885aa3d..00000000
--- a/pricenode/src/main/java/bisq/price/mining/providers/MempoolFeeRateProvider.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * This file is part of Haveno.
- *
- * Haveno is free software: you can redistribute it and/or modify it
- * under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at
- * your option) any later version.
- *
- * Haveno is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with Haveno. If not, see .
- */
-
-package bisq.price.mining.providers;
-
-import bisq.price.PriceController;
-import bisq.price.mining.FeeRate;
-import bisq.price.mining.FeeRateProvider;
-
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.context.annotation.Primary;
-import org.springframework.core.ParameterizedTypeReference;
-import org.springframework.core.annotation.Order;
-import org.springframework.core.env.CommandLinePropertySource;
-import org.springframework.core.env.Environment;
-import org.springframework.http.RequestEntity;
-import org.springframework.stereotype.Component;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.client.RestTemplate;
-import org.springframework.web.util.UriComponentsBuilder;
-
-import java.time.Duration;
-import java.time.Instant;
-
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-
-/**
- * {@link FeeRateProvider} that interprets the Mempool API format to retrieve a mining
- * fee estimate. See https://mempool.space.
- */
-abstract class MempoolFeeRateProvider extends FeeRateProvider {
-
- private static final int DEFAULT_MAX_BLOCKS = 2;
- private static final int DEFAULT_REFRESH_INTERVAL = 2;
-
- // Keys of properties defining the available Mempool API endpoints. To enable them,
- // simply uncomment and adjust the corresponding lines in application.properties
- private static final String MEMPOOL_HOSTNAME_KEY_1 = "bisq.price.mining.providers.mempoolHostname.1";
- private static final String MEMPOOL_HOSTNAME_KEY_2 = "bisq.price.mining.providers.mempoolHostname.2";
- private static final String MEMPOOL_HOSTNAME_KEY_3 = "bisq.price.mining.providers.mempoolHostname.3";
- private static final String MEMPOOL_HOSTNAME_KEY_4 = "bisq.price.mining.providers.mempoolHostname.4";
- private static final String MEMPOOL_HOSTNAME_KEY_5 = "bisq.price.mining.providers.mempoolHostname.5";
-
- private static final RestTemplate restTemplate = new RestTemplate();
-
- // TODO: As of the switch to the mempool.space API this field and related members are
- // now dead code and should be removed, including removing the positional
- // command-line argument from startup scripts. Operators need to be notified of this
- // when it happens.
- private final int maxBlocks;
-
- protected Environment env;
-
- public MempoolFeeRateProvider(Environment env) {
- super(Duration.ofMinutes(refreshInterval(env)));
- this.env = env;
- this.maxBlocks = maxBlocks(env);
- }
-
- protected FeeRate doGet() {
- // Default value is the minimum rate. If the connection to the fee estimate
- // provider fails, we fall back to this value.
- try {
- return getEstimatedFeeRate();
- }
- catch (Exception e) {
- // Something happened with the connection
- log.error("Error retrieving bitcoin mining fee estimation: " + e.getMessage());
- }
-
- return new FeeRate("BTC", MIN_FEE_RATE_FOR_TRADING, MIN_FEE_RATE_FOR_WITHDRAWAL, Instant.now().getEpochSecond());
- }
-
- private FeeRate getEstimatedFeeRate() {
- Set> feeRatePredictions = getFeeRatePredictions();
- long estimatedFeeRate = feeRatePredictions.stream()
- .filter(p -> p.getKey().equalsIgnoreCase("halfHourFee"))
- .map(Map.Entry::getValue)
- .findFirst()
- .map(r -> Math.max(r, MIN_FEE_RATE_FOR_TRADING))
- .map(r -> Math.min(r, MAX_FEE_RATE))
- .orElse(MIN_FEE_RATE_FOR_TRADING);
- long minimumFee = feeRatePredictions.stream()
- .filter(p -> p.getKey().equalsIgnoreCase("minimumFee"))
- .map(Map.Entry::getValue)
- .findFirst()
- .map(r -> Math.multiplyExact(r, 2)) // multiply the minimumFee by 2 (per wiz)
- .orElse(MIN_FEE_RATE_FOR_WITHDRAWAL);
- log.info("Retrieved estimated mining fee of {} sat/vB and minimumFee of {} sat/vB from {}", estimatedFeeRate, minimumFee, getMempoolApiHostname());
- return new FeeRate("BTC", estimatedFeeRate, minimumFee, Instant.now().getEpochSecond());
- }
-
- private Set> getFeeRatePredictions() {
- return restTemplate.exchange(
- RequestEntity
- .get(UriComponentsBuilder
- // See https://github.com/bisq-network/projects/issues/27
- .fromUriString("https://" + getMempoolApiHostname() + "/api/v1/fees/recommended")
- .build().toUri())
- .build(),
- new ParameterizedTypeReference