mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-24 07:07:43 +01:00
Merge remote-tracking branch 'bisq-network/release/v1.3.9' into upgrade-javafax-14
This commit is contained in:
commit
fbe43c53ed
32 changed files with 509 additions and 136 deletions
|
@ -48,14 +48,14 @@
|
|||
run ./bisq-cli --password="xyz" getversion
|
||||
[ "$status" -eq 0 ]
|
||||
echo "actual output: $output" >&2
|
||||
[ "$output" = "1.3.7" ]
|
||||
[ "$output" = "1.3.8" ]
|
||||
}
|
||||
|
||||
@test "test getversion" {
|
||||
run ./bisq-cli --password=xyz getversion
|
||||
[ "$status" -eq 0 ]
|
||||
echo "actual output: $output" >&2
|
||||
[ "$output" = "1.3.7" ]
|
||||
[ "$output" = "1.3.8" ]
|
||||
}
|
||||
|
||||
@test "test setwalletpassword \"a b c\"" {
|
||||
|
|
|
@ -27,6 +27,8 @@ import joptsimple.OptionParser;
|
|||
import joptsimple.OptionSet;
|
||||
import joptsimple.OptionSpec;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -169,7 +171,7 @@ public class ApiTestConfig {
|
|||
ArgumentAcceptingOptionSpec<String> bitcoinRegtestHostOpt =
|
||||
parser.accepts(BITCOIN_REGTEST_HOST, "Bitcoin Core regtest host")
|
||||
.withRequiredArg()
|
||||
.ofType(String.class).defaultsTo("localhost");
|
||||
.ofType(String.class).defaultsTo(InetAddress.getLoopbackAddress().getHostAddress());
|
||||
|
||||
ArgumentAcceptingOptionSpec<Integer> bitcoinRpcPortOpt =
|
||||
parser.accepts(BITCOIN_RPC_PORT, "Bitcoin Core rpc port (non-default)")
|
||||
|
|
|
@ -17,16 +17,20 @@
|
|||
|
||||
package bisq.apitest;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static bisq.apitest.config.BisqAppConfig.alicedaemon;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
|
||||
|
||||
|
||||
import bisq.apitest.config.ApiTestConfig;
|
||||
import bisq.apitest.config.BisqAppConfig;
|
||||
import bisq.apitest.method.BitcoinCliHelper;
|
||||
import bisq.cli.GrpcStubs;
|
||||
|
||||
|
@ -57,34 +61,41 @@ import bisq.cli.GrpcStubs;
|
|||
*/
|
||||
public class ApiTestCase {
|
||||
|
||||
// The gRPC service stubs are used by method & scenario tests, but not e2e tests.
|
||||
protected static GrpcStubs grpcStubs;
|
||||
|
||||
protected static Scaffold scaffold;
|
||||
protected static ApiTestConfig config;
|
||||
protected static BitcoinCliHelper bitcoinCli;
|
||||
|
||||
// gRPC service stubs are used by method & scenario tests, but not e2e tests.
|
||||
private static final Map<BisqAppConfig, GrpcStubs> grpcStubsCache = new HashMap<>();
|
||||
|
||||
public static void setUpScaffold(String supportingApps)
|
||||
throws InterruptedException, ExecutionException, IOException {
|
||||
scaffold = new Scaffold(supportingApps).setUp();
|
||||
config = scaffold.config;
|
||||
bitcoinCli = new BitcoinCliHelper((config));
|
||||
// For now, all grpc requests are sent to the alicedaemon, but this will need to
|
||||
// be made configurable for new test cases that call arb or bob node daemons.
|
||||
grpcStubs = new GrpcStubs("localhost", alicedaemon.apiPort, config.apiPassword);
|
||||
}
|
||||
|
||||
public static void setUpScaffold(String[] params)
|
||||
throws InterruptedException, ExecutionException, IOException {
|
||||
scaffold = new Scaffold(params).setUp();
|
||||
config = scaffold.config;
|
||||
grpcStubs = new GrpcStubs("localhost", alicedaemon.apiPort, config.apiPassword);
|
||||
}
|
||||
|
||||
public static void tearDownScaffold() {
|
||||
scaffold.tearDown();
|
||||
}
|
||||
|
||||
protected static GrpcStubs grpcStubs(BisqAppConfig bisqAppConfig) {
|
||||
if (grpcStubsCache.containsKey(bisqAppConfig)) {
|
||||
return grpcStubsCache.get(bisqAppConfig);
|
||||
} else {
|
||||
GrpcStubs stubs = new GrpcStubs(InetAddress.getLoopbackAddress().getHostAddress(),
|
||||
bisqAppConfig.apiPort, config.apiPassword);
|
||||
grpcStubsCache.put(bisqAppConfig, stubs);
|
||||
return stubs;
|
||||
}
|
||||
}
|
||||
|
||||
protected void sleep(long ms) {
|
||||
try {
|
||||
MILLISECONDS.sleep(ms);
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.junit.jupiter.api.Order;
|
|||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
|
||||
import static bisq.apitest.config.BisqAppConfig.alicedaemon;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
@ -57,7 +58,8 @@ public class GetBalanceTest extends MethodTest {
|
|||
public void testGetBalance() {
|
||||
// All tests depend on the DAO / regtest environment, and Alice's wallet is
|
||||
// initialized with 10 BTC during the scaffolding setup.
|
||||
var balance = grpcStubs.walletsService.getBalance(GetBalanceRequest.newBuilder().build()).getBalance();
|
||||
var balance = grpcStubs(alicedaemon).walletsService
|
||||
.getBalance(GetBalanceRequest.newBuilder().build()).getBalance();
|
||||
assertEquals(1000000000, balance);
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,8 @@ public class GetVersionTest extends MethodTest {
|
|||
@Test
|
||||
@Order(1)
|
||||
public void testGetVersion() {
|
||||
var version = grpcStubs.versionService.getVersion(GetVersionRequest.newBuilder().build()).getVersion();
|
||||
var version = grpcStubs(alicedaemon).versionService
|
||||
.getVersion(GetVersionRequest.newBuilder().build()).getVersion();
|
||||
assertEquals(VERSION, version);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,13 +20,17 @@ package bisq.apitest.method;
|
|||
import bisq.proto.grpc.GetBalanceRequest;
|
||||
import bisq.proto.grpc.GetFundingAddressesRequest;
|
||||
import bisq.proto.grpc.LockWalletRequest;
|
||||
import bisq.proto.grpc.RegisterDisputeAgentRequest;
|
||||
import bisq.proto.grpc.RemoveWalletPasswordRequest;
|
||||
import bisq.proto.grpc.SetWalletPasswordRequest;
|
||||
import bisq.proto.grpc.UnlockWalletRequest;
|
||||
|
||||
import static bisq.common.app.DevEnv.DEV_PRIVILEGE_PRIV_KEY;
|
||||
|
||||
|
||||
|
||||
import bisq.apitest.ApiTestCase;
|
||||
import bisq.apitest.config.BisqAppConfig;
|
||||
|
||||
public class MethodTest extends ApiTestCase {
|
||||
|
||||
|
@ -60,24 +64,31 @@ public class MethodTest extends ApiTestCase {
|
|||
return GetFundingAddressesRequest.newBuilder().build();
|
||||
}
|
||||
|
||||
protected final RegisterDisputeAgentRequest createRegisterDisputeAgentRequest(String disputeAgentType) {
|
||||
return RegisterDisputeAgentRequest.newBuilder()
|
||||
.setDisputeAgentType(disputeAgentType)
|
||||
.setRegistrationKey(DEV_PRIVILEGE_PRIV_KEY).build();
|
||||
}
|
||||
|
||||
// Convenience methods for calling frequently used & thoroughly tested gRPC services.
|
||||
|
||||
protected final long getBalance() {
|
||||
return grpcStubs.walletsService.getBalance(createBalanceRequest()).getBalance();
|
||||
protected final long getBalance(BisqAppConfig bisqAppConfig) {
|
||||
return grpcStubs(bisqAppConfig).walletsService.getBalance(createBalanceRequest()).getBalance();
|
||||
}
|
||||
|
||||
protected final void unlockWallet(String password, long timeout) {
|
||||
protected final void unlockWallet(BisqAppConfig bisqAppConfig, String password, long timeout) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
grpcStubs.walletsService.unlockWallet(createUnlockWalletRequest(password, timeout));
|
||||
grpcStubs(bisqAppConfig).walletsService.unlockWallet(createUnlockWalletRequest(password, timeout));
|
||||
}
|
||||
|
||||
protected final void lockWallet() {
|
||||
protected final void lockWallet(BisqAppConfig bisqAppConfig) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
grpcStubs.walletsService.lockWallet(createLockWalletRequest());
|
||||
grpcStubs(bisqAppConfig).walletsService.lockWallet(createLockWalletRequest());
|
||||
}
|
||||
|
||||
protected final String getUnusedBtcAddress() {
|
||||
return grpcStubs.walletsService.getFundingAddresses(createGetFundingAddressesRequest())
|
||||
protected final String getUnusedBtcAddress(BisqAppConfig bisqAppConfig) {
|
||||
//noinspection OptionalGetWithoutIsPresent
|
||||
return grpcStubs(bisqAppConfig).walletsService.getFundingAddresses(createGetFundingAddressesRequest())
|
||||
.getAddressBalanceInfoList()
|
||||
.stream()
|
||||
.filter(a -> a.getBalance() == 0 && a.getNumConfirmations() == 0)
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.apitest.method;
|
||||
|
||||
import bisq.proto.grpc.RegisterDisputeAgentRequest;
|
||||
|
||||
import io.grpc.StatusRuntimeException;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
|
||||
import static bisq.apitest.config.BisqAppConfig.arbdaemon;
|
||||
import static bisq.common.app.DevEnv.DEV_PRIVILEGE_PRIV_KEY;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
|
||||
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
@Slf4j
|
||||
@TestMethodOrder(OrderAnnotation.class)
|
||||
public class RegisterDisputeAgentsTest extends MethodTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void setUp() {
|
||||
try {
|
||||
setUpScaffold("bitcoind,seednode,arbdaemon");
|
||||
} catch (Exception ex) {
|
||||
fail(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
public void testRegisterArbitratorShouldThrowException() {
|
||||
var req =
|
||||
createRegisterDisputeAgentRequest("arbitrator");
|
||||
Throwable exception = assertThrows(StatusRuntimeException.class, () ->
|
||||
grpcStubs(arbdaemon).disputeAgentsService.registerDisputeAgent(req));
|
||||
assertEquals("INVALID_ARGUMENT: arbitrators must be registered in a Bisq UI",
|
||||
exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
public void testInvalidDisputeAgentTypeArgShouldThrowException() {
|
||||
var req =
|
||||
createRegisterDisputeAgentRequest("badagent");
|
||||
Throwable exception = assertThrows(StatusRuntimeException.class, () ->
|
||||
grpcStubs(arbdaemon).disputeAgentsService.registerDisputeAgent(req));
|
||||
assertEquals("INVALID_ARGUMENT: unknown dispute agent type badagent",
|
||||
exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
public void testInvalidRegistrationKeyArgShouldThrowException() {
|
||||
var req = RegisterDisputeAgentRequest.newBuilder()
|
||||
.setDisputeAgentType("refundagent")
|
||||
.setRegistrationKey("invalid" + DEV_PRIVILEGE_PRIV_KEY).build();
|
||||
Throwable exception = assertThrows(StatusRuntimeException.class, () ->
|
||||
grpcStubs(arbdaemon).disputeAgentsService.registerDisputeAgent(req));
|
||||
assertEquals("INVALID_ARGUMENT: invalid registration key",
|
||||
exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(4)
|
||||
public void testRegisterMediator() {
|
||||
var req =
|
||||
createRegisterDisputeAgentRequest("mediator");
|
||||
grpcStubs(arbdaemon).disputeAgentsService.registerDisputeAgent(req);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(5)
|
||||
public void testRegisterRefundAgent() {
|
||||
var req =
|
||||
createRegisterDisputeAgentRequest("refundagent");
|
||||
grpcStubs(arbdaemon).disputeAgentsService.registerDisputeAgent(req);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void tearDown() {
|
||||
tearDownScaffold();
|
||||
}
|
||||
}
|
|
@ -36,13 +36,13 @@ public class WalletProtectionTest extends MethodTest {
|
|||
@Order(1)
|
||||
public void testSetWalletPassword() {
|
||||
var request = createSetWalletPasswordRequest("first-password");
|
||||
grpcStubs.walletsService.setWalletPassword(request);
|
||||
grpcStubs(alicedaemon).walletsService.setWalletPassword(request);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
public void testGetBalanceOnEncryptedWalletShouldThrowException() {
|
||||
Throwable exception = assertThrows(StatusRuntimeException.class, this::getBalance);
|
||||
Throwable exception = assertThrows(StatusRuntimeException.class, () -> getBalance(alicedaemon));
|
||||
assertEquals("UNKNOWN: wallet is locked", exception.getMessage());
|
||||
}
|
||||
|
||||
|
@ -50,11 +50,10 @@ public class WalletProtectionTest extends MethodTest {
|
|||
@Order(3)
|
||||
public void testUnlockWalletFor4Seconds() {
|
||||
var request = createUnlockWalletRequest("first-password", 4);
|
||||
grpcStubs.walletsService.unlockWallet(request);
|
||||
getBalance(); // should not throw 'wallet locked' exception
|
||||
|
||||
grpcStubs(alicedaemon).walletsService.unlockWallet(request);
|
||||
getBalance(alicedaemon); // should not throw 'wallet locked' exception
|
||||
sleep(4500); // let unlock timeout expire
|
||||
Throwable exception = assertThrows(StatusRuntimeException.class, this::getBalance);
|
||||
Throwable exception = assertThrows(StatusRuntimeException.class, () -> getBalance(alicedaemon));
|
||||
assertEquals("UNKNOWN: wallet is locked", exception.getMessage());
|
||||
}
|
||||
|
||||
|
@ -62,20 +61,19 @@ public class WalletProtectionTest extends MethodTest {
|
|||
@Order(4)
|
||||
public void testGetBalanceAfterUnlockTimeExpiryShouldThrowException() {
|
||||
var request = createUnlockWalletRequest("first-password", 3);
|
||||
grpcStubs.walletsService.unlockWallet(request);
|
||||
grpcStubs(alicedaemon).walletsService.unlockWallet(request);
|
||||
sleep(4000); // let unlock timeout expire
|
||||
Throwable exception = assertThrows(StatusRuntimeException.class, this::getBalance);
|
||||
Throwable exception = assertThrows(StatusRuntimeException.class, () -> getBalance(alicedaemon));
|
||||
assertEquals("UNKNOWN: wallet is locked", exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(5)
|
||||
public void testLockWalletBeforeUnlockTimeoutExpiry() {
|
||||
unlockWallet("first-password", 60);
|
||||
unlockWallet(alicedaemon, "first-password", 60);
|
||||
var request = createLockWalletRequest();
|
||||
grpcStubs.walletsService.lockWallet(request);
|
||||
|
||||
Throwable exception = assertThrows(StatusRuntimeException.class, this::getBalance);
|
||||
grpcStubs(alicedaemon).walletsService.lockWallet(request);
|
||||
Throwable exception = assertThrows(StatusRuntimeException.class, () -> getBalance(alicedaemon));
|
||||
assertEquals("UNKNOWN: wallet is locked", exception.getMessage());
|
||||
}
|
||||
|
||||
|
@ -83,40 +81,39 @@ public class WalletProtectionTest extends MethodTest {
|
|||
@Order(6)
|
||||
public void testLockWalletWhenWalletAlreadyLockedShouldThrowException() {
|
||||
var request = createLockWalletRequest();
|
||||
|
||||
Throwable exception = assertThrows(StatusRuntimeException.class, () ->
|
||||
grpcStubs.walletsService.lockWallet(request));
|
||||
grpcStubs(alicedaemon).walletsService.lockWallet(request));
|
||||
assertEquals("UNKNOWN: wallet is already locked", exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(7)
|
||||
public void testUnlockWalletTimeoutOverride() {
|
||||
unlockWallet("first-password", 2);
|
||||
unlockWallet(alicedaemon, "first-password", 2);
|
||||
sleep(500); // override unlock timeout after 0.5s
|
||||
unlockWallet("first-password", 6);
|
||||
unlockWallet(alicedaemon, "first-password", 6);
|
||||
sleep(5000);
|
||||
getBalance(); // getbalance 5s after resetting unlock timeout to 6s
|
||||
getBalance(alicedaemon); // getbalance 5s after resetting unlock timeout to 6s
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(8)
|
||||
public void testSetNewWalletPassword() {
|
||||
var request = createSetWalletPasswordRequest("first-password", "second-password");
|
||||
grpcStubs.walletsService.setWalletPassword(request);
|
||||
|
||||
unlockWallet("second-password", 2);
|
||||
getBalance();
|
||||
var request = createSetWalletPasswordRequest(
|
||||
"first-password", "second-password");
|
||||
grpcStubs(alicedaemon).walletsService.setWalletPassword(request);
|
||||
unlockWallet(alicedaemon, "second-password", 2);
|
||||
getBalance(alicedaemon);
|
||||
sleep(2500); // allow time for wallet save
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(9)
|
||||
public void testSetNewWalletPasswordWithIncorrectNewPasswordShouldThrowException() {
|
||||
var request = createSetWalletPasswordRequest("bad old password", "irrelevant");
|
||||
|
||||
var request = createSetWalletPasswordRequest(
|
||||
"bad old password", "irrelevant");
|
||||
Throwable exception = assertThrows(StatusRuntimeException.class, () ->
|
||||
grpcStubs.walletsService.setWalletPassword(request));
|
||||
grpcStubs(alicedaemon).walletsService.setWalletPassword(request));
|
||||
assertEquals("UNKNOWN: incorrect old password", exception.getMessage());
|
||||
}
|
||||
|
||||
|
@ -124,8 +121,8 @@ public class WalletProtectionTest extends MethodTest {
|
|||
@Order(10)
|
||||
public void testRemoveNewWalletPassword() {
|
||||
var request = createRemoveWalletPasswordRequest("second-password");
|
||||
grpcStubs.walletsService.removeWalletPassword(request);
|
||||
getBalance(); // should not throw 'wallet locked' exception
|
||||
grpcStubs(alicedaemon).walletsService.removeWalletPassword(request);
|
||||
getBalance(alicedaemon); // should not throw 'wallet locked' exception
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.junit.jupiter.api.Order;
|
|||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
|
||||
import static bisq.apitest.config.BisqAppConfig.alicedaemon;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
@ -48,16 +49,17 @@ public class FundWalletScenarioTest extends ScenarioTest {
|
|||
@Test
|
||||
@Order(1)
|
||||
public void testFundWallet() {
|
||||
long balance = getBalance(); // bisq wallet was initialized with 10 btc
|
||||
// bisq wallet was initialized with 10 btc
|
||||
long balance = getBalance(alicedaemon);
|
||||
assertEquals(1000000000, balance);
|
||||
|
||||
String unusedAddress = getUnusedBtcAddress();
|
||||
String unusedAddress = getUnusedBtcAddress(alicedaemon);
|
||||
bitcoinCli.sendToAddress(unusedAddress, "2.5");
|
||||
|
||||
bitcoinCli.generateBlocks(1);
|
||||
sleep(1500);
|
||||
|
||||
balance = getBalance();
|
||||
balance = getBalance(alicedaemon);
|
||||
assertEquals(1250000000L, balance); // new balance is 12.5 btc
|
||||
}
|
||||
|
||||
|
|
|
@ -376,7 +376,7 @@ configure(project(':desktop')) {
|
|||
apply plugin: 'witness'
|
||||
apply from: '../gradle/witness/gradle-witness.gradle'
|
||||
|
||||
version = '1.3.8-SNAPSHOT'
|
||||
version = '1.3.9-SNAPSHOT'
|
||||
|
||||
mainClassName = 'bisq.desktop.app.BisqAppMain'
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package bisq.cli;
|
||||
|
||||
import bisq.proto.grpc.DisputeAgentsGrpc;
|
||||
import bisq.proto.grpc.GetVersionGrpc;
|
||||
import bisq.proto.grpc.OffersGrpc;
|
||||
import bisq.proto.grpc.PaymentAccountsGrpc;
|
||||
|
@ -29,6 +30,7 @@ import static java.util.concurrent.TimeUnit.SECONDS;
|
|||
|
||||
public class GrpcStubs {
|
||||
|
||||
public final DisputeAgentsGrpc.DisputeAgentsBlockingStub disputeAgentsService;
|
||||
public final GetVersionGrpc.GetVersionBlockingStub versionService;
|
||||
public final OffersGrpc.OffersBlockingStub offersService;
|
||||
public final PaymentAccountsGrpc.PaymentAccountsBlockingStub paymentAccountsService;
|
||||
|
@ -46,6 +48,7 @@ public class GrpcStubs {
|
|||
}
|
||||
}));
|
||||
|
||||
this.disputeAgentsService = DisputeAgentsGrpc.newBlockingStub(channel).withCallCredentials(credentials);
|
||||
this.versionService = GetVersionGrpc.newBlockingStub(channel).withCallCredentials(credentials);
|
||||
this.offersService = OffersGrpc.newBlockingStub(channel).withCallCredentials(credentials);
|
||||
this.paymentAccountsService = PaymentAccountsGrpc.newBlockingStub(channel).withCallCredentials(credentials);
|
||||
|
|
|
@ -27,7 +27,7 @@ public class Version {
|
|||
// VERSION = 0.5.0 introduces proto buffer for the P2P network and local DB and is a not backward compatible update
|
||||
// Therefore all sub versions start again with 1
|
||||
// We use semantic versioning with major, minor and patch
|
||||
public static final String VERSION = "1.3.8";
|
||||
public static final String VERSION = "1.3.9";
|
||||
|
||||
public static int getMajorVersion(String version) {
|
||||
return getSubVersion(version, 0);
|
||||
|
|
|
@ -29,6 +29,8 @@ import java.util.Optional;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
public class MathUtils {
|
||||
private static final Logger log = LoggerFactory.getLogger(MathUtils.class);
|
||||
|
||||
|
@ -127,24 +129,30 @@ public class MathUtils {
|
|||
}
|
||||
|
||||
public Optional<Double> next(long val) {
|
||||
var fullAtStart = isFull();
|
||||
if (fullAtStart) {
|
||||
if (outlier > 0) {
|
||||
// Return early if it's an outlier
|
||||
var avg = (double) sum / size;
|
||||
if (Math.abs(avg - val) / avg > outlier) {
|
||||
return Optional.empty();
|
||||
try {
|
||||
var fullAtStart = isFull();
|
||||
if (fullAtStart) {
|
||||
if (outlier > 0) {
|
||||
// Return early if it's an outlier
|
||||
checkArgument(size != 0);
|
||||
var avg = (double) sum / size;
|
||||
if (Math.abs(avg - val) / avg > outlier) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
sum -= window.remove();
|
||||
}
|
||||
sum -= window.remove();
|
||||
window.add(val);
|
||||
sum += val;
|
||||
if (!fullAtStart && isFull() && outlier != 0) {
|
||||
removeInitialOutlier();
|
||||
}
|
||||
// When discarding outliers, the first n non discarded elements return Optional.empty()
|
||||
return outlier > 0 && !isFull() ? Optional.empty() : current();
|
||||
} catch (Throwable t) {
|
||||
log.error(t.toString());
|
||||
return Optional.empty();
|
||||
}
|
||||
window.add(val);
|
||||
sum += val;
|
||||
if (!fullAtStart && isFull() && outlier != 0) {
|
||||
removeInitialOutlier();
|
||||
}
|
||||
// When discarding outliers, the first n non discarded elements return Optional.empty()
|
||||
return outlier > 0 && !isFull() ? Optional.empty() : current();
|
||||
}
|
||||
|
||||
boolean isFull() {
|
||||
|
@ -155,7 +163,9 @@ public class MathUtils {
|
|||
var element = window.iterator();
|
||||
while (element.hasNext()) {
|
||||
var val = element.next();
|
||||
var avgExVal = (double) (sum - val) / (size - 1);
|
||||
int div = size - 1;
|
||||
checkArgument(div != 0);
|
||||
var avgExVal = (double) (sum - val) / div;
|
||||
if (Math.abs(avgExVal - val) / avgExVal > outlier) {
|
||||
element.remove();
|
||||
break;
|
||||
|
|
|
@ -47,26 +47,38 @@ import lombok.extern.slf4j.Slf4j;
|
|||
@Slf4j
|
||||
public class CoreApi {
|
||||
|
||||
private final CoreDisputeAgentsService coreDisputeAgentsService;
|
||||
private final CoreOffersService coreOffersService;
|
||||
private final CorePaymentAccountsService paymentAccountsService;
|
||||
private final CoreWalletsService walletsService;
|
||||
private final TradeStatisticsManager tradeStatisticsManager;
|
||||
|
||||
@Inject
|
||||
public CoreApi(CoreOffersService coreOffersService,
|
||||
public CoreApi(CoreDisputeAgentsService coreDisputeAgentsService,
|
||||
CoreOffersService coreOffersService,
|
||||
CorePaymentAccountsService paymentAccountsService,
|
||||
CoreWalletsService walletsService,
|
||||
TradeStatisticsManager tradeStatisticsManager) {
|
||||
this.coreDisputeAgentsService = coreDisputeAgentsService;
|
||||
this.coreOffersService = coreOffersService;
|
||||
this.paymentAccountsService = paymentAccountsService;
|
||||
this.walletsService = walletsService;
|
||||
this.tradeStatisticsManager = tradeStatisticsManager;
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameReturnValue")
|
||||
public String getVersion() {
|
||||
return Version.VERSION;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Dispute Agents
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void registerDisputeAgent(String disputeAgentType, String registrationKey) {
|
||||
coreDisputeAgentsService.registerDisputeAgent(disputeAgentType, registrationKey);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Offers
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
144
core/src/main/java/bisq/core/api/CoreDisputeAgentsService.java
Normal file
144
core/src/main/java/bisq/core/api/CoreDisputeAgentsService.java
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.core.api;
|
||||
|
||||
import bisq.core.support.dispute.mediation.mediator.Mediator;
|
||||
import bisq.core.support.dispute.mediation.mediator.MediatorManager;
|
||||
import bisq.core.support.dispute.refund.refundagent.RefundAgent;
|
||||
import bisq.core.support.dispute.refund.refundagent.RefundAgentManager;
|
||||
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
import bisq.network.p2p.P2PService;
|
||||
|
||||
import bisq.common.config.Config;
|
||||
import bisq.common.crypto.KeyRing;
|
||||
|
||||
import org.bitcoinj.core.ECKey;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import static bisq.common.app.DevEnv.DEV_PRIVILEGE_PRIV_KEY;
|
||||
import static java.net.InetAddress.getLoopbackAddress;
|
||||
|
||||
@Slf4j
|
||||
class CoreDisputeAgentsService {
|
||||
|
||||
private final Config config;
|
||||
private final KeyRing keyRing;
|
||||
private final MediatorManager mediatorManager;
|
||||
private final RefundAgentManager refundAgentManager;
|
||||
private final P2PService p2PService;
|
||||
private final NodeAddress nodeAddress;
|
||||
private final List<String> languageCodes;
|
||||
|
||||
@Inject
|
||||
public CoreDisputeAgentsService(Config config,
|
||||
KeyRing keyRing,
|
||||
MediatorManager mediatorManager,
|
||||
RefundAgentManager refundAgentManager,
|
||||
P2PService p2PService) {
|
||||
this.config = config;
|
||||
this.keyRing = keyRing;
|
||||
this.mediatorManager = mediatorManager;
|
||||
this.refundAgentManager = refundAgentManager;
|
||||
this.p2PService = p2PService;
|
||||
this.nodeAddress = new NodeAddress(getLoopbackAddress().getHostAddress(), config.nodePort);
|
||||
this.languageCodes = Arrays.asList("de", "en", "es", "fr");
|
||||
}
|
||||
|
||||
public void registerDisputeAgent(String disputeAgentType, String registrationKey) {
|
||||
if (!p2PService.isBootstrapped())
|
||||
throw new IllegalStateException("p2p service is not bootstrapped yet");
|
||||
|
||||
if (config.baseCurrencyNetwork.isMainnet()
|
||||
|| config.baseCurrencyNetwork.isDaoBetaNet()
|
||||
|| !config.useLocalhostForP2P)
|
||||
throw new IllegalStateException("dispute agents must be registered in a Bisq UI");
|
||||
|
||||
if (!registrationKey.equals(DEV_PRIVILEGE_PRIV_KEY))
|
||||
throw new IllegalArgumentException("invalid registration key");
|
||||
|
||||
ECKey ecKey;
|
||||
String signature;
|
||||
switch (disputeAgentType) {
|
||||
case "arbitrator":
|
||||
throw new IllegalArgumentException("arbitrators must be registered in a Bisq UI");
|
||||
case "mediator":
|
||||
ecKey = mediatorManager.getRegistrationKey(registrationKey);
|
||||
signature = mediatorManager.signStorageSignaturePubKey(Objects.requireNonNull(ecKey));
|
||||
registerMediator(nodeAddress, languageCodes, ecKey, signature);
|
||||
return;
|
||||
case "refundagent":
|
||||
ecKey = refundAgentManager.getRegistrationKey(registrationKey);
|
||||
signature = refundAgentManager.signStorageSignaturePubKey(Objects.requireNonNull(ecKey));
|
||||
registerRefundAgent(nodeAddress, languageCodes, ecKey, signature);
|
||||
return;
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown dispute agent type " + disputeAgentType);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerMediator(NodeAddress nodeAddress,
|
||||
List<String> languageCodes,
|
||||
ECKey ecKey,
|
||||
String signature) {
|
||||
Mediator mediator = new Mediator(nodeAddress,
|
||||
keyRing.getPubKeyRing(),
|
||||
languageCodes,
|
||||
new Date().getTime(),
|
||||
ecKey.getPubKey(),
|
||||
signature,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
mediatorManager.addDisputeAgent(mediator, () -> {
|
||||
}, errorMessage -> {
|
||||
});
|
||||
mediatorManager.getDisputeAgentByNodeAddress(nodeAddress).orElseThrow(() ->
|
||||
new IllegalStateException("could not register mediator"));
|
||||
}
|
||||
|
||||
private void registerRefundAgent(NodeAddress nodeAddress,
|
||||
List<String> languageCodes,
|
||||
ECKey ecKey,
|
||||
String signature) {
|
||||
RefundAgent refundAgent = new RefundAgent(nodeAddress,
|
||||
keyRing.getPubKeyRing(),
|
||||
languageCodes,
|
||||
new Date().getTime(),
|
||||
ecKey.getPubKey(),
|
||||
signature,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
refundAgentManager.addDisputeAgent(refundAgent, () -> {
|
||||
}, errorMessage -> {
|
||||
});
|
||||
refundAgentManager.getDisputeAgentByNodeAddress(nodeAddress).orElseThrow(() ->
|
||||
new IllegalStateException("could not register refund agent"));
|
||||
}
|
||||
}
|
|
@ -35,7 +35,7 @@ shared.no=No
|
|||
shared.iUnderstand=I understand
|
||||
shared.na=N/A
|
||||
shared.shutDown=Shut down
|
||||
shared.reportBug=Report bug at GitHub issues
|
||||
shared.reportBug=Report bug on GitHub
|
||||
shared.buyBitcoin=Buy bitcoin
|
||||
shared.sellBitcoin=Sell bitcoin
|
||||
shared.buyCurrency=Buy {0}
|
||||
|
@ -94,21 +94,21 @@ shared.BTCMinMax=BTC (min - max)
|
|||
shared.removeOffer=Remove offer
|
||||
shared.dontRemoveOffer=Don't remove offer
|
||||
shared.editOffer=Edit offer
|
||||
shared.openLargeQRWindow=Open large QR-Code window
|
||||
shared.openLargeQRWindow=Open large QR code window
|
||||
shared.tradingAccount=Trading account
|
||||
shared.faq=Visit FAQ web page
|
||||
shared.faq=Visit FAQ page
|
||||
shared.yesCancel=Yes, cancel
|
||||
shared.nextStep=Next step
|
||||
shared.selectTradingAccount=Select trading account
|
||||
shared.fundFromSavingsWalletButton=Transfer funds from Bisq wallet
|
||||
shared.fundFromExternalWalletButton=Open your external wallet for funding
|
||||
shared.openDefaultWalletFailed=Opening a default Bitcoin wallet application has failed. Perhaps you don't have one installed?
|
||||
shared.openDefaultWalletFailed=Failed to open a Bitcoin wallet application. Are you sure you have one installed?
|
||||
shared.distanceInPercent=Distance in % from market price
|
||||
shared.belowInPercent=Below % from market price
|
||||
shared.aboveInPercent=Above % from market price
|
||||
shared.enterPercentageValue=Enter % value
|
||||
shared.OR=OR
|
||||
shared.notEnoughFunds=You don''t have enough funds in your Bisq wallet.\nYou need {0} but you have only {1} in your Bisq wallet.\n\nPlease fund the trade from an external Bitcoin wallet or fund your Bisq wallet at \"Funds/Receive funds\".
|
||||
shared.notEnoughFunds=You don''t have enough funds in your Bisq wallet for this transaction—{0} is needed but only {1} is available.\n\nPlease add funds from an external wallet, or fund your Bisq wallet at Funds > Receive Funds.
|
||||
shared.waitingForFunds=Waiting for funds...
|
||||
shared.depositTransactionId=Deposit transaction ID
|
||||
shared.TheBTCBuyer=The BTC buyer
|
||||
|
@ -116,22 +116,22 @@ shared.You=You
|
|||
shared.reasonForPayment=Reason for payment
|
||||
shared.sendingConfirmation=Sending confirmation...
|
||||
shared.sendingConfirmationAgain=Please send confirmation again
|
||||
shared.exportCSV=Export to csv
|
||||
shared.exportCSV=Export to CSV
|
||||
shared.exportJSON=Export to JSON
|
||||
shared.noDateAvailable=No date available
|
||||
shared.noDetailsAvailable=No details available
|
||||
shared.notUsedYet=Not used yet
|
||||
shared.date=Date
|
||||
shared.sendFundsDetailsWithFee=Sending: {0}\nFrom address: {1}\nTo receiving address: {2}.\nRequired mining fee is: {3} ({4} satoshis/byte)\nTransaction size: {5} Kb\n\nThe recipient will receive: {6}\n\nAre you sure you want to withdraw this amount?
|
||||
shared.sendFundsDetailsDust=Bisq detected that this transaction would create a change output which is below the minimum dust threshold (and not allowed by Bitcoin consensus rules). Instead, this dust ({0} satoshi{1}) will be added to the mining fee.\n\n\n
|
||||
shared.sendFundsDetailsDust=Bisq detected that this transaction would create a change output which is below the minimum dust threshold (and therefore not allowed by Bitcoin consensus rules). Instead, this dust ({0} satoshi{1}) will be added to the mining fee.\n\n\n
|
||||
shared.copyToClipboard=Copy to clipboard
|
||||
shared.language=Language
|
||||
shared.country=Country
|
||||
shared.applyAndShutDown=Apply and shut down
|
||||
shared.selectPaymentMethod=Select payment method
|
||||
shared.accountNameAlreadyUsed=That account name is already used in a saved account.\nPlease use another name.
|
||||
shared.accountNameAlreadyUsed=That account name is already used for another saved account.\nPlease choose another name.
|
||||
shared.askConfirmDeleteAccount=Do you really want to delete the selected account?
|
||||
shared.cannotDeleteAccount=You cannot delete that account because it is used in an open offer or in a trade.
|
||||
shared.cannotDeleteAccount=You cannot delete that account because it is being used in an open offer (or in an open trade).
|
||||
shared.noAccountsSetupYet=There are no accounts set up yet
|
||||
shared.manageAccounts=Manage accounts
|
||||
shared.addNewAccount=Add new account
|
||||
|
@ -375,10 +375,10 @@ offerbook.deactivateOffer.failed=Deactivating of offer failed:\n{0}
|
|||
offerbook.activateOffer.failed=Publishing of offer failed:\n{0}
|
||||
offerbook.withdrawFundsHint=You can withdraw the funds you paid in from the {0} screen.
|
||||
|
||||
offerbook.warning.noTradingAccountForCurrency.headline=No trading account for selected currency
|
||||
offerbook.warning.noTradingAccountForCurrency.msg=You don't have a trading account for the selected currency.\nDo you want to create an offer with one of your existing trading accounts?
|
||||
offerbook.warning.noMatchingAccount.headline=No matching trading account.
|
||||
offerbook.warning.noMatchingAccount.msg=To take this offer, you will need to set up a payment account using this payment method.\n\nWould you like to do this now?
|
||||
offerbook.warning.noTradingAccountForCurrency.headline=No payment account for selected currency
|
||||
offerbook.warning.noTradingAccountForCurrency.msg=You don't have a payment account set up for the selected currency.\n\nWould you like to create an offer for another currency instead?
|
||||
offerbook.warning.noMatchingAccount.headline=No matching payment account.
|
||||
offerbook.warning.noMatchingAccount.msg=This offer uses a payment method you haven't set up yet. \n\nWould you like to set up a new payment account now?
|
||||
|
||||
offerbook.warning.counterpartyTradeRestrictions=This offer cannot be taken due to counterparty trade restrictions
|
||||
|
||||
|
@ -2512,8 +2512,8 @@ offerDetailsWindow.confirm.taker=Confirm: Take offer to {0} bitcoin
|
|||
offerDetailsWindow.creationDate=Creation date
|
||||
offerDetailsWindow.makersOnion=Maker's onion address
|
||||
|
||||
qRCodeWindow.headline=QR-Code
|
||||
qRCodeWindow.msg=Please use that QR-Code for funding your Bisq wallet from your external wallet.
|
||||
qRCodeWindow.headline=QR Code
|
||||
qRCodeWindow.msg=Please use this QR code for funding your Bisq wallet from your external wallet.
|
||||
qRCodeWindow.request=Payment request:\n{0}
|
||||
|
||||
selectDepositTxWindow.headline=Select deposit transaction for dispute
|
||||
|
@ -2859,8 +2859,8 @@ systemTray.tooltip=Bisq: A decentralized bitcoin exchange network
|
|||
# GUI Util
|
||||
####################################################################
|
||||
|
||||
guiUtil.miningFeeInfo=Please be sure that the mining fee used at your external wallet is \
|
||||
at least {0} satoshis/byte. Otherwise the trade transactions cannot be confirmed and a trade would end up in a dispute.
|
||||
guiUtil.miningFeeInfo=Please be sure that the mining fee used by your external wallet is \
|
||||
at least {0} satoshis/byte. Otherwise the trade transactions may not be confirmed in time and the trade will end up in a dispute.
|
||||
|
||||
guiUtil.accountExport.savedToPath=Trading accounts saved to path:\n{0}
|
||||
guiUtil.accountExport.noAccountSetup=You don't have trading accounts set up for exporting.
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
package bisq.daemon.grpc;
|
||||
|
||||
import bisq.core.api.CoreApi;
|
||||
|
||||
import bisq.proto.grpc.DisputeAgentsGrpc;
|
||||
import bisq.proto.grpc.RegisterDisputeAgentReply;
|
||||
import bisq.proto.grpc.RegisterDisputeAgentRequest;
|
||||
|
||||
import io.grpc.Status;
|
||||
import io.grpc.StatusRuntimeException;
|
||||
import io.grpc.stub.StreamObserver;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
class GrpcDisputeAgentsService extends DisputeAgentsGrpc.DisputeAgentsImplBase {
|
||||
|
||||
private final CoreApi coreApi;
|
||||
|
||||
@Inject
|
||||
public GrpcDisputeAgentsService(CoreApi coreApi) {
|
||||
this.coreApi = coreApi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerDisputeAgent(RegisterDisputeAgentRequest req,
|
||||
StreamObserver<RegisterDisputeAgentReply> responseObserver) {
|
||||
try {
|
||||
coreApi.registerDisputeAgent(req.getDisputeAgentType(), req.getRegistrationKey());
|
||||
var reply = RegisterDisputeAgentReply.newBuilder().build();
|
||||
responseObserver.onNext(reply);
|
||||
responseObserver.onCompleted();
|
||||
} catch (IllegalArgumentException cause) {
|
||||
var ex = new StatusRuntimeException(Status.INVALID_ARGUMENT.withDescription(cause.getMessage()));
|
||||
responseObserver.onError(ex);
|
||||
throw ex;
|
||||
} catch (IllegalStateException cause) {
|
||||
var ex = new StatusRuntimeException(Status.UNKNOWN.withDescription(cause.getMessage()));
|
||||
responseObserver.onError(ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -51,11 +51,13 @@ public class GrpcServer {
|
|||
@Inject
|
||||
public GrpcServer(Config config,
|
||||
CoreApi coreApi,
|
||||
GrpcDisputeAgentsService disputeAgentsService,
|
||||
GrpcOffersService offersService,
|
||||
GrpcPaymentAccountsService paymentAccountsService,
|
||||
GrpcWalletsService walletsService) {
|
||||
this.coreApi = coreApi;
|
||||
this.server = ServerBuilder.forPort(config.apiPort)
|
||||
.addService(disputeAgentsService)
|
||||
.addService(new GetVersionService())
|
||||
.addService(new GetTradeStatisticsService())
|
||||
.addService(offersService)
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
# pull base image
|
||||
FROM openjdk:8-jdk
|
||||
ENV version 1.3.8-SNAPSHOT
|
||||
ENV version 1.3.9-SNAPSHOT
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends openjfx && rm -rf /var/lib/apt/lists/* &&
|
||||
apt-get install -y vim fakeroot
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# - Update version below
|
||||
# - Ensure JAVA_HOME below is pointing to OracleJDK 10 directory
|
||||
|
||||
version=1.3.8-SNAPSHOT
|
||||
version=1.3.9-SNAPSHOT
|
||||
version_base=$(echo $version | awk -F'[_-]' '{print $1}')
|
||||
if [ ! -f "$JAVA_HOME/bin/javapackager" ]; then
|
||||
if [ -d "/usr/lib/jvm/jdk-10.0.2" ]; then
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# Prior to running this script:
|
||||
# - Update version below
|
||||
|
||||
version=1.3.8-SNAPSHOT
|
||||
version=1.3.9-SNAPSHOT
|
||||
base_dir=$( cd "$(dirname "$0")" ; pwd -P )/../../..
|
||||
package_dir=$base_dir/desktop/package
|
||||
release_dir=$base_dir/desktop/release/$version
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
<!-- See: https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -->
|
||||
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.3.8</string>
|
||||
<string>1.3.9</string>
|
||||
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.3.8</string>
|
||||
<string>1.3.9</string>
|
||||
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>Bisq</string>
|
||||
|
|
|
@ -6,7 +6,7 @@ mkdir -p deploy
|
|||
|
||||
set -e
|
||||
|
||||
version="1.3.8-SNAPSHOT"
|
||||
version="1.3.9-SNAPSHOT"
|
||||
|
||||
cd ..
|
||||
./gradlew :desktop:build -x test shadowJar
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
cd ../../
|
||||
|
||||
version="1.3.8-SNAPSHOT"
|
||||
version="1.3.9-SNAPSHOT"
|
||||
|
||||
target_dir="releases/$version"
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
cd $(dirname $0)/../../../
|
||||
|
||||
version=1.3.8
|
||||
version=1.3.9
|
||||
|
||||
find . -type f \( -name "finalize.sh" \
|
||||
-o -name "create_app.sh" \
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
cd $(dirname $0)/../../../
|
||||
|
||||
oldVersion=1.3.7
|
||||
newVersion=1.3.8
|
||||
oldVersion=1.3.8
|
||||
newVersion=1.3.9
|
||||
|
||||
find . -type f \( -name "finalize.sh" \
|
||||
-o -name "create_app.sh" \
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
@echo off
|
||||
|
||||
set version=1.3.8-SNAPSHOT
|
||||
set version=1.3.9-SNAPSHOT
|
||||
if not exist "%JAVA_HOME%\bin\javapackager.exe" (
|
||||
if not exist "%ProgramFiles%\Java\jdk-10.0.2" (
|
||||
echo Javapackager not found. Update JAVA_HOME variable to point to OracleJDK.
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
@echo off
|
||||
|
||||
set version=1.3.8-SNAPSHOT
|
||||
set version=1.3.9-SNAPSHOT
|
||||
set release_dir=%~dp0..\..\..\releases\%version%
|
||||
set package_dir=%~dp0..
|
||||
|
||||
|
|
|
@ -335,37 +335,42 @@ public abstract class MutableOfferDataModel extends OfferDataModel implements Bs
|
|||
|
||||
private void setSuggestedSecurityDeposit(PaymentAccount paymentAccount) {
|
||||
var minSecurityDeposit = preferences.getBuyerSecurityDepositAsPercent(getPaymentAccount());
|
||||
if (getTradeCurrency() == null) {
|
||||
setBuyerSecurityDeposit(minSecurityDeposit, false);
|
||||
return;
|
||||
}
|
||||
// Get average historic prices over for the prior trade period equaling the lock time
|
||||
var blocksRange = Restrictions.getLockTime(paymentAccount.getPaymentMethod().isAsset());
|
||||
var startDate = new Date(System.currentTimeMillis() - blocksRange * 10 * 60000);
|
||||
var sortedRangeData = tradeStatisticsManager.getObservableTradeStatisticsSet().stream()
|
||||
.filter(e -> e.getCurrencyCode().equals(getTradeCurrency().getCode()))
|
||||
.filter(e -> e.getTradeDate().compareTo(startDate) >= 0)
|
||||
.sorted(Comparator.comparing(TradeStatistics2::getTradeDate))
|
||||
.collect(Collectors.toList());
|
||||
var movingAverage = new MathUtils.MovingAverage(10, 0.2);
|
||||
double[] extremes = {Double.MAX_VALUE, Double.MIN_VALUE};
|
||||
sortedRangeData.forEach(e -> {
|
||||
var price = e.getTradePrice().getValue();
|
||||
movingAverage.next(price).ifPresent(val -> {
|
||||
if (val < extremes[0]) extremes[0] = val;
|
||||
if (val > extremes[1]) extremes[1] = val;
|
||||
try {
|
||||
if (getTradeCurrency() == null) {
|
||||
setBuyerSecurityDeposit(minSecurityDeposit, false);
|
||||
return;
|
||||
}
|
||||
// Get average historic prices over for the prior trade period equaling the lock time
|
||||
var blocksRange = Restrictions.getLockTime(paymentAccount.getPaymentMethod().isAsset());
|
||||
var startDate = new Date(System.currentTimeMillis() - blocksRange * 10 * 60000);
|
||||
var sortedRangeData = tradeStatisticsManager.getObservableTradeStatisticsSet().stream()
|
||||
.filter(e -> e.getCurrencyCode().equals(getTradeCurrency().getCode()))
|
||||
.filter(e -> e.getTradeDate().compareTo(startDate) >= 0)
|
||||
.sorted(Comparator.comparing(TradeStatistics2::getTradeDate))
|
||||
.collect(Collectors.toList());
|
||||
var movingAverage = new MathUtils.MovingAverage(10, 0.2);
|
||||
double[] extremes = {Double.MAX_VALUE, Double.MIN_VALUE};
|
||||
sortedRangeData.forEach(e -> {
|
||||
var price = e.getTradePrice().getValue();
|
||||
movingAverage.next(price).ifPresent(val -> {
|
||||
if (val < extremes[0]) extremes[0] = val;
|
||||
if (val > extremes[1]) extremes[1] = val;
|
||||
});
|
||||
});
|
||||
});
|
||||
var min = extremes[0];
|
||||
var max = extremes[1];
|
||||
if (min == 0d || max == 0d) {
|
||||
setBuyerSecurityDeposit(minSecurityDeposit, false);
|
||||
return;
|
||||
var min = extremes[0];
|
||||
var max = extremes[1];
|
||||
if (min == 0d || max == 0d) {
|
||||
setBuyerSecurityDeposit(minSecurityDeposit, false);
|
||||
return;
|
||||
}
|
||||
// Suggested deposit is double the trade range over the previous lock time period, bounded by min/max deposit
|
||||
var suggestedSecurityDeposit =
|
||||
Math.min(2 * (max - min) / max, Restrictions.getMaxBuyerSecurityDepositAsPercent());
|
||||
buyerSecurityDeposit.set(Math.max(suggestedSecurityDeposit, minSecurityDeposit));
|
||||
} catch (Throwable t) {
|
||||
log.error(t.toString());
|
||||
buyerSecurityDeposit.set(minSecurityDeposit);
|
||||
}
|
||||
// Suggested deposit is double the trade range over the previous lock time period, bounded by min/max deposit
|
||||
var suggestedSecurityDeposit =
|
||||
Math.min(2 * (max - min) / max, Restrictions.getMaxBuyerSecurityDepositAsPercent());
|
||||
buyerSecurityDeposit.set(Math.max(suggestedSecurityDeposit, minSecurityDeposit));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -24,19 +24,20 @@ option java_package = "bisq.proto.grpc";
|
|||
option java_multiple_files = true;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Version
|
||||
// DisputeAgents
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
service GetVersion {
|
||||
rpc GetVersion (GetVersionRequest) returns (GetVersionReply) {
|
||||
service DisputeAgents {
|
||||
rpc RegisterDisputeAgent (RegisterDisputeAgentRequest) returns (RegisterDisputeAgentReply) {
|
||||
}
|
||||
}
|
||||
|
||||
message GetVersionRequest {
|
||||
message RegisterDisputeAgentRequest {
|
||||
string disputeAgentType = 1;
|
||||
string registrationKey = 2;
|
||||
}
|
||||
|
||||
message GetVersionReply {
|
||||
string version = 1;
|
||||
message RegisterDisputeAgentReply {
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -214,3 +215,20 @@ message AddressBalanceInfo {
|
|||
int64 balance = 2;
|
||||
int64 numConfirmations = 3;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Version
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
service GetVersion {
|
||||
rpc GetVersion (GetVersionRequest) returns (GetVersionReply) {
|
||||
}
|
||||
}
|
||||
|
||||
message GetVersionRequest {
|
||||
}
|
||||
|
||||
message GetVersionReply {
|
||||
string version = 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
1.3.8-SNAPSHOT
|
||||
1.3.9-SNAPSHOT
|
||||
|
|
|
@ -33,7 +33,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||
|
||||
@Slf4j
|
||||
public class SeedNodeMain extends ExecutableForAppWithP2p {
|
||||
private static final String VERSION = "1.3.8";
|
||||
private static final String VERSION = "1.3.9";
|
||||
private SeedNode seedNode;
|
||||
|
||||
public SeedNodeMain() {
|
||||
|
|
Loading…
Add table
Reference in a new issue