diff --git a/Makefile b/Makefile
index 7bca61db..cf2866e0 100644
--- a/Makefile
+++ b/Makefile
@@ -595,3 +595,15 @@ user3-desktop-mainnet:
--apiPort=1204 \
--useNativeXmrWallet=false \
--ignoreLocalXmrNode=false \
+
+parner1-bot-stagenet:
+ ./haveno-bot$(APP_EXT) \
+ --baseCurrencyNetwork=XMR_STAGENET \
+ --useLocalhostForP2P=false \
+ --useDevPrivilegeKeys=false \
+ --nodePort=9999 \
+ --appName=haveno-XMR_STAGENET_user3 \
+ --apiPassword=apitest \
+ --apiPort=1204 \
+ --useNativeXmrWallet=false \
+ --ignoreLocalXmrNode=false \
\ No newline at end of file
diff --git a/bot/src/main/java/haveno/bot/app/HavenoBot.java b/bot/src/main/java/haveno/bot/app/HavenoBot.java
new file mode 100644
index 00000000..c5098f99
--- /dev/null
+++ b/bot/src/main/java/haveno/bot/app/HavenoBot.java
@@ -0,0 +1,64 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq 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.
+ *
+ * Bisq 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 Bisq. If not, see .
+ */
+
+ /*
+ * This file is part of Haveno Multi-Platform by Kewbit.
+ *
+ * Bisq 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.
+ *
+ * Bisq 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 Bisq. If not, see .
+ */
+
+package haveno.bot.app;
+
+import com.google.inject.Injector;
+import haveno.core.app.misc.AppSetup;
+import haveno.core.app.misc.AppSetupWithP2P;
+import haveno.core.network.p2p.inventory.GetInventoryRequestHandler;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class HavenoBot {
+ @Setter
+ private Injector injector;
+ private AppSetup appSetup;
+ private GetInventoryRequestHandler getInventoryRequestHandler;
+
+ public HavenoBot() {
+ }
+
+ public void startApplication() {
+ appSetup = injector.getInstance(AppSetupWithP2P.class);
+ appSetup.start();
+
+ getInventoryRequestHandler = injector.getInstance(GetInventoryRequestHandler.class);
+ }
+
+ public void shutDown() {
+ getInventoryRequestHandler.shutDown();
+ }
+}
\ No newline at end of file
diff --git a/bot/src/main/java/haveno/bot/app/HavenoBotMain.java b/bot/src/main/java/haveno/bot/app/HavenoBotMain.java
new file mode 100644
index 00000000..60b9868f
--- /dev/null
+++ b/bot/src/main/java/haveno/bot/app/HavenoBotMain.java
@@ -0,0 +1,187 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq 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.
+ *
+ * Bisq 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 Bisq. If not, see .
+ */
+
+package haveno.bot.app;
+
+import haveno.common.UserThread;
+import haveno.common.app.AppModule;
+import haveno.common.handlers.ResultHandler;
+import lombok.extern.slf4j.Slf4j;
+
+import haveno.common.Timer;
+import haveno.common.config.BaseCurrencyNetwork;
+import haveno.common.config.Config;
+import haveno.core.app.TorSetup;
+import haveno.core.app.misc.ExecutableForAppWithP2p;
+import haveno.core.app.misc.ModuleForAppWithP2p;
+import haveno.core.user.Cookie;
+import haveno.core.user.CookieKey;
+import haveno.core.user.User;
+import haveno.network.p2p.P2PService;
+import haveno.network.p2p.P2PServiceListener;
+import haveno.network.p2p.peers.PeerManager;
+
+@Slf4j
+public class HavenoBotMain extends ExecutableForAppWithP2p {
+
+ private static final long CHECK_CONNECTION_LOSS_SEC = 30;
+ private static final String VERSION = "1.1.2";
+ private HavenoBot bot;
+ private Timer checkConnectionLossTime;
+
+ public HavenoBotMain() {
+ super("Haveno Bot", "haveno-bot", "haveno_bot", VERSION);
+ }
+
+ public static void main(String[] args) {
+ System.out.println("HavenoBot.VERSION: " + VERSION);
+ new HavenoBotMain().execute(args);
+ }
+
+ @Override
+ protected int doExecute() {
+ super.doExecute();
+
+ checkMemory(config, this);
+
+ return keepRunning();
+ }
+
+ @Override
+ protected void addCapabilities() {
+ }
+
+ @Override
+ protected void launchApplication() {
+ UserThread.execute(() -> {
+ try {
+ bot = new HavenoBot();
+ UserThread.execute(this::onApplicationLaunched);
+ } catch (Exception e) {
+ log.error("Error launching haveno bot: {}\n", e.toString(), e);
+ }
+ });
+ }
+
+ @Override
+ protected void onApplicationLaunched() {
+ super.onApplicationLaunched();
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // We continue with a series of synchronous execution tasks
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ protected AppModule getModule() {
+ return new ModuleForAppWithP2p(config);
+ }
+
+ @Override
+ protected void applyInjector() {
+ super.applyInjector();
+
+ bot.setInjector(injector);
+
+ }
+
+ @Override
+ protected void startApplication() {
+ Cookie cookie = injector.getInstance(User.class).getCookie();
+ cookie.getAsOptionalBoolean(CookieKey.CLEAN_TOR_DIR_AT_RESTART).ifPresent(wasCleanTorDirSet -> {
+ if (wasCleanTorDirSet) {
+ injector.getInstance(TorSetup.class).cleanupTorFiles(() -> {
+ log.info("Tor directory reset");
+ cookie.remove(CookieKey.CLEAN_TOR_DIR_AT_RESTART);
+ }, log::error);
+ }
+ });
+
+ bot.startApplication();
+
+ injector.getInstance(P2PService.class).addP2PServiceListener(new P2PServiceListener() {
+ @Override
+ public void onDataReceived() {
+ // Do nothing
+ }
+
+ @Override
+ public void onNoSeedNodeAvailable() {
+ // Do nothing
+ }
+
+ @Override
+ public void onNoPeersAvailable() {
+ // Do nothing
+ }
+
+ @Override
+ public void onUpdatedDataReceived() {
+ // Do nothing
+ }
+
+ @Override
+ public void onTorNodeReady() {
+ // Do nothing
+ }
+
+ @Override
+ public void onHiddenServicePublished() {
+ UserThread.runAfter(() -> setupConnectionLossCheck(), 60);
+ }
+
+ @Override
+ public void onSetupFailed(Throwable throwable) {
+ // Do nothing
+ }
+
+ @Override
+ public void onRequestCustomBridges() {
+ // Do nothing
+ }
+ });
+ }
+
+ private void setupConnectionLossCheck() {
+ // For dev testing (usually on XMR_LOCAL) we don't want to get the seed shut
+ // down as it is normal that the seed is the only actively running node.
+ if (Config.baseCurrencyNetwork() != BaseCurrencyNetwork.XMR_MAINNET) {
+ return;
+ }
+
+ if (checkConnectionLossTime != null) {
+ return;
+ }
+
+ checkConnectionLossTime = UserThread.runPeriodically(() -> {
+ if (injector.getInstance(PeerManager.class).getNumAllConnectionsLostEvents() > 1) {
+ // We set a flag to clear tor cache files at re-start. We cannot clear it now as Tor is used and
+ // that can cause problems.
+ injector.getInstance(User.class).getCookie().putAsBoolean(CookieKey.CLEAN_TOR_DIR_AT_RESTART, true);
+ shutDown(this);
+ }
+ }, CHECK_CONNECTION_LOSS_SEC);
+
+ }
+
+ @Override
+ public void gracefulShutDown(ResultHandler resultHandler) {
+ bot.shutDown();
+ super.gracefulShutDown(resultHandler);
+ }
+}
diff --git a/bot/src/main/resources/logback.xml b/bot/src/main/resources/logback.xml
new file mode 100644
index 00000000..f838048e
--- /dev/null
+++ b/bot/src/main/resources/logback.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+ %hl2(%d{MMM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{40}: %msg %xEx%n)
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build.gradle b/build.gradle
index 295ccc3d..0f4e82ac 100644
--- a/build.gradle
+++ b/build.gradle
@@ -132,7 +132,8 @@ configure([project(':cli'),
project(':seednode'),
project(':statsnode'),
project(':inventory'),
- project(':apitest')]) {
+ project(':apitest'),
+ project(':bot')]) {
apply plugin: 'application'
@@ -735,6 +736,71 @@ configure(project(':daemon')) {
}
}
+configure(project(':bot')) {
+ apply plugin: 'com.github.johnrengelman.shadow'
+ apply plugin: 'application'
+
+ application {
+ mainClass = 'haveno.bot.app.HavenoBotMain'
+ }
+
+ dependencies {
+ implementation project(':proto')
+ implementation project(':common')
+ implementation project(':p2p')
+ implementation project(':core')
+ annotationProcessor "org.projectlombok:lombok:$lombokVersion"
+ compileOnly "javax.annotation:javax.annotation-api:$javaxAnnotationVersion"
+ compileOnly "org.projectlombok:lombok:$lombokVersion"
+ implementation "ch.qos.logback:logback-classic:$logbackVersion"
+ implementation "ch.qos.logback:logback-core:$logbackVersion"
+ implementation "com.google.code.gson:gson:$gsonVersion"
+ implementation "com.google.guava:guava:$guavaVersion"
+ implementation "com.google.protobuf:protobuf-java:$protobufVersion"
+ implementation "org.apache.commons:commons-lang3:$langVersion"
+ implementation "org.jetbrains:annotations:$jetbrainsAnnotationsVersion"
+ implementation "org.slf4j:slf4j-api:$slf4jVersion"
+ implementation("com.github.bisq-network:bitcoinj:$bitcoinjVersion") {
+ exclude(module: 'bcprov-jdk15on')
+ exclude(module: 'guava')
+ exclude(module: 'jsr305')
+ exclude(module: 'okhttp')
+ exclude(module: 'okio')
+ exclude(module: 'protobuf-java')
+ exclude(module: 'slf4j-api')
+ }
+ implementation("com.google.inject:guice:$guiceVersion") {
+ exclude(module: 'guava')
+ }
+ implementation("io.grpc:grpc-protobuf:$grpcVersion") {
+ exclude(module: 'animal-sniffer-annotations')
+ exclude(module: 'guava')
+ }
+ implementation("io.grpc:grpc-stub:$grpcVersion") {
+ exclude(module: 'animal-sniffer-annotations')
+ exclude(module: 'guava')
+ }
+ runtimeOnly("io.grpc:grpc-netty-shaded:$grpcVersion") {
+ exclude(module: 'animal-sniffer-annotations')
+ exclude(module: 'guava')
+ }
+ 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"
+ testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:$jupiterVersion")
+
+ implementation("io.github.woodser:monero-java:$moneroJavaVersion") {
+ exclude(module: 'jackson-core')
+ exclude(module: 'jackson-annotations')
+ exclude(module: 'jackson-databind')
+ exclude(module: 'bcprov-jdk15on')
+ exclude(group: 'org.slf4j', module: 'slf4j-simple')
+ }
+ implementation "org.openjfx:javafx-base:$javafxVersion:$os"
+ implementation "org.openjfx:javafx-graphics:$javafxVersion:$os"
+ }
+}
configure(project(':inventory')) {
apply plugin: 'com.github.johnrengelman.shadow'
diff --git a/core/src/main/java/haveno/core/alert/AlertManager.java b/core/src/main/java/haveno/core/alert/AlertManager.java
index a54f45c4..cf60e545 100644
--- a/core/src/main/java/haveno/core/alert/AlertManager.java
+++ b/core/src/main/java/haveno/core/alert/AlertManager.java
@@ -97,25 +97,13 @@ public class AlertManager {
}
protected List getPubKeyList() {
- if (useDevPrivilegeKeys) return List.of(DevEnv.DEV_PRIVILEGE_PUB_KEY);
- switch (Config.baseCurrencyNetwork()) {
- case XMR_LOCAL:
- return List.of(
- "027a381b5333a56e1cc3d90d3a7d07f26509adf7029ed06fc997c656621f8da1ee",
- "024baabdba90e7cc0dc4626ef73ea9d722ea7085d1104491da8c76f28187513492");
- case XMR_STAGENET:
- return List.of(
- "036d8a1dfcb406886037d2381da006358722823e1940acc2598c844bbc0fd1026f",
- "026c581ad773d987e6bd10785ac7f7e0e64864aedeb8bce5af37046de812a37854",
- "025b058c9f2c60d839669dbfa5578cf5a8117d60e6b70e2f0946f8a691273c6a36");
- case XMR_MAINNET:
- return List.of();
- default:
- throw new RuntimeException("Unhandled base currency network: " + Config.baseCurrencyNetwork());
- }
+ return List.of(
+ "0326b14f3a55d02575dceed5202b8b125f458cbe0fdceeee294b443bf1a8d8cf78",
+ "03d62d14438adbe7aea688ade1f73933c6f0a705f238c02c5b54b83dd1e4fca225",
+ "023c8fdea9ff2d03daef54337907e70a7b0e20084a75fcc3ad2f0c28d8b691dea1"
+ );
}
-
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
diff --git a/core/src/main/java/haveno/core/alert/PrivateNotificationManager.java b/core/src/main/java/haveno/core/alert/PrivateNotificationManager.java
index fd6abac5..5aa84c86 100644
--- a/core/src/main/java/haveno/core/alert/PrivateNotificationManager.java
+++ b/core/src/main/java/haveno/core/alert/PrivateNotificationManager.java
@@ -96,22 +96,11 @@ public class PrivateNotificationManager implements MessageListener {
}
protected List getPubKeyList() {
- if (useDevPrivilegeKeys) return List.of(DevEnv.DEV_PRIVILEGE_PUB_KEY);
- switch (Config.baseCurrencyNetwork()) {
- case XMR_LOCAL:
- return List.of(
- "027a381b5333a56e1cc3d90d3a7d07f26509adf7029ed06fc997c656621f8da1ee",
- "024baabdba90e7cc0dc4626ef73ea9d722ea7085d1104491da8c76f28187513492");
- case XMR_STAGENET:
- return List.of(
- "02ba7c5de295adfe57b60029f3637a2c6b1d0e969a8aaefb9e0ddc3a7963f26925",
- "026c581ad773d987e6bd10785ac7f7e0e64864aedeb8bce5af37046de812a37854",
- "025b058c9f2c60d839669dbfa5578cf5a8117d60e6b70e2f0946f8a691273c6a36");
- case XMR_MAINNET:
- return List.of();
- default:
- throw new RuntimeException("Unhandled base currency network: " + Config.baseCurrencyNetwork());
- }
+ return List.of(
+ "0326b14f3a55d02575dceed5202b8b125f458cbe0fdceeee294b443bf1a8d8cf78",
+ "03d62d14438adbe7aea688ade1f73933c6f0a705f238c02c5b54b83dd1e4fca225",
+ "023c8fdea9ff2d03daef54337907e70a7b0e20084a75fcc3ad2f0c28d8b691dea1"
+ );
}
private void handleMessage(DecryptedMessageWithPubKey decryptedMessageWithPubKey, NodeAddress senderNodeAddress) {
diff --git a/core/src/main/java/haveno/core/filter/FilterManager.java b/core/src/main/java/haveno/core/filter/FilterManager.java
index 2cebb66f..37f8eca9 100644
--- a/core/src/main/java/haveno/core/filter/FilterManager.java
+++ b/core/src/main/java/haveno/core/filter/FilterManager.java
@@ -114,11 +114,11 @@ public class FilterManager {
this.providersRepository = providersRepository;
this.ignoreDevMsg = ignoreDevMsg;
- publicKeys = useDevPrivilegeKeys ?
- Collections.singletonList(DevEnv.DEV_PRIVILEGE_PUB_KEY) :
- List.of("0358d47858acdc41910325fce266571540681ef83a0d6fedce312bef9810793a27",
- "029340c3e7d4bb0f9e651b5f590b434fecb6175aeaa57145c7804ff05d210e534f",
- "034dc7530bf66ffd9580aa98031ea9a18ac2d269f7c56c0e71eca06105b9ed69f9");
+ publicKeys = List.of(
+ "0326b14f3a55d02575dceed5202b8b125f458cbe0fdceeee294b443bf1a8d8cf78",
+ "03d62d14438adbe7aea688ade1f73933c6f0a705f238c02c5b54b83dd1e4fca225",
+ "023c8fdea9ff2d03daef54337907e70a7b0e20084a75fcc3ad2f0c28d8b691dea1"
+ );
banFilter.setBannedNodePredicate(this::isNodeAddressBannedFromNetwork);
}
diff --git a/core/src/main/java/haveno/core/support/dispute/arbitration/arbitrator/ArbitratorManager.java b/core/src/main/java/haveno/core/support/dispute/arbitration/arbitrator/ArbitratorManager.java
index 30fe0be1..781ae7a4 100644
--- a/core/src/main/java/haveno/core/support/dispute/arbitration/arbitrator/ArbitratorManager.java
+++ b/core/src/main/java/haveno/core/support/dispute/arbitration/arbitrator/ArbitratorManager.java
@@ -59,29 +59,11 @@ public class ArbitratorManager extends DisputeAgentManager {
@Override
protected List getPubKeyList() {
- switch (Config.baseCurrencyNetwork()) {
- case XMR_LOCAL:
- return List.of(
- "027a381b5333a56e1cc3d90d3a7d07f26509adf7029ed06fc997c656621f8da1ee",
- "024baabdba90e7cc0dc4626ef73ea9d722ea7085d1104491da8c76f28187513492",
- "026eeec3c119dd6d537249d74e5752a642dd2c3cc5b6a9b44588eb58344f29b519");
- case XMR_STAGENET:
- return List.of(
- "03bb559ce207a4deb51d4c705076c95b85ad8581d35936b2a422dcb504eaf7cdb0",
- "026c581ad773d987e6bd10785ac7f7e0e64864aedeb8bce5af37046de812a37854",
- "025b058c9f2c60d839669dbfa5578cf5a8117d60e6b70e2f0946f8a691273c6a36",
- "036c7d3f4bf05ef39b9d1b0a5d453a18210de36220c3d83cd16e59bd6132b037ad",
- "030f7122a10ff73cd73808bddace95be77a94189c8a0eb24586265e125ce5ce6b9",
- "03aa23e062afa0dda465f46986f8aa8d0374ad3e3f256141b05681dcb1e39c3859",
- "02d3beb1293ca2ca14e6d42ca8bd18089a62aac62fd6bb23923ee6ead46ac60fba",
- "03fa0f38f27bdd324db6f933f7e57851dadf3b911e4db6b19dd0950492c4525a31",
- "02a1a458df5acf4ab08fdca748e28f33a955a30854c8c1a831ee733dca7f0d2fcd",
- "0374dd70f3fa6e47ec5ab97932e1cec6233e98e6ae3129036b17118650c44fd3de");
- case XMR_MAINNET:
- return List.of();
- default:
- throw new RuntimeException("Unhandled base currency network: " + Config.baseCurrencyNetwork());
- }
+ return List.of(
+ "0326b14f3a55d02575dceed5202b8b125f458cbe0fdceeee294b443bf1a8d8cf78",
+ "03d62d14438adbe7aea688ade1f73933c6f0a705f238c02c5b54b83dd1e4fca225",
+ "023c8fdea9ff2d03daef54337907e70a7b0e20084a75fcc3ad2f0c28d8b691dea1"
+ );
}
@Override
diff --git a/settings.gradle b/settings.gradle
index 2d96ad24..1f9f7a9f 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -12,5 +12,6 @@ include 'seednode'
include 'statsnode'
include 'inventory'
include 'apitest'
+include 'bot'
rootProject.name = 'haveno'