mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 09:52:23 +01:00
Merge remote-tracking branch 'origin/master' into HEAD
This commit is contained in:
commit
fabd592938
@ -1,8 +1,6 @@
|
|||||||
# This doc specifies who gets requested to review GitHub pull requests.
|
# This doc specifies who gets requested to review GitHub pull requests.
|
||||||
# See https://help.github.com/articles/about-codeowners/.
|
# See https://help.github.com/articles/about-codeowners/.
|
||||||
|
|
||||||
*gradle* @cbeams
|
|
||||||
/pricenode/ @cbeams
|
|
||||||
/core/main/java/bisq/core/dao/ @ManfredKarrer
|
/core/main/java/bisq/core/dao/ @ManfredKarrer
|
||||||
|
|
||||||
# For seednode configuration changes
|
# For seednode configuration changes
|
||||||
|
@ -97,4 +97,5 @@ See the issues in the [bisq-network/style](https://github.com/bisq-network/style
|
|||||||
|
|
||||||
- [contributor checklist](https://docs.bisq.network/contributor-checklist.html)
|
- [contributor checklist](https://docs.bisq.network/contributor-checklist.html)
|
||||||
- [developer docs](docs#readme) including build and dev environment setup instructions
|
- [developer docs](docs#readme) including build and dev environment setup instructions
|
||||||
|
- [project management process](https://bisq.wiki/Project_management)
|
||||||
|
|
||||||
|
@ -378,7 +378,7 @@ configure(project(':desktop')) {
|
|||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
apply from: '../gradle/witness/gradle-witness.gradle'
|
apply from: '../gradle/witness/gradle-witness.gradle'
|
||||||
|
|
||||||
version = '1.3.4-SNAPSHOT'
|
version = '1.3.5-SNAPSHOT'
|
||||||
|
|
||||||
mainClassName = 'bisq.desktop.app.BisqAppMain'
|
mainClassName = 'bisq.desktop.app.BisqAppMain'
|
||||||
|
|
||||||
|
@ -17,14 +17,21 @@
|
|||||||
|
|
||||||
package bisq.cli;
|
package bisq.cli;
|
||||||
|
|
||||||
|
import bisq.proto.grpc.CreatePaymentAccountRequest;
|
||||||
|
import bisq.proto.grpc.GetAddressBalanceRequest;
|
||||||
import bisq.proto.grpc.GetBalanceRequest;
|
import bisq.proto.grpc.GetBalanceRequest;
|
||||||
|
import bisq.proto.grpc.GetFundingAddressesRequest;
|
||||||
|
import bisq.proto.grpc.GetOffersRequest;
|
||||||
|
import bisq.proto.grpc.GetPaymentAccountsRequest;
|
||||||
import bisq.proto.grpc.GetVersionGrpc;
|
import bisq.proto.grpc.GetVersionGrpc;
|
||||||
import bisq.proto.grpc.GetVersionRequest;
|
import bisq.proto.grpc.GetVersionRequest;
|
||||||
import bisq.proto.grpc.LockWalletRequest;
|
import bisq.proto.grpc.LockWalletRequest;
|
||||||
|
import bisq.proto.grpc.OffersGrpc;
|
||||||
|
import bisq.proto.grpc.PaymentAccountsGrpc;
|
||||||
import bisq.proto.grpc.RemoveWalletPasswordRequest;
|
import bisq.proto.grpc.RemoveWalletPasswordRequest;
|
||||||
import bisq.proto.grpc.SetWalletPasswordRequest;
|
import bisq.proto.grpc.SetWalletPasswordRequest;
|
||||||
import bisq.proto.grpc.UnlockWalletRequest;
|
import bisq.proto.grpc.UnlockWalletRequest;
|
||||||
import bisq.proto.grpc.WalletGrpc;
|
import bisq.proto.grpc.WalletsGrpc;
|
||||||
|
|
||||||
import io.grpc.ManagedChannelBuilder;
|
import io.grpc.ManagedChannelBuilder;
|
||||||
import io.grpc.StatusRuntimeException;
|
import io.grpc.StatusRuntimeException;
|
||||||
@ -32,32 +39,39 @@ import io.grpc.StatusRuntimeException;
|
|||||||
import joptsimple.OptionParser;
|
import joptsimple.OptionParser;
|
||||||
import joptsimple.OptionSet;
|
import joptsimple.OptionSet;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import static bisq.cli.CurrencyFormat.formatSatoshis;
|
||||||
|
import static bisq.cli.TableFormat.formatAddressBalanceTbl;
|
||||||
|
import static bisq.cli.TableFormat.formatOfferTable;
|
||||||
|
import static bisq.cli.TableFormat.formatPaymentAcctTbl;
|
||||||
import static java.lang.String.format;
|
import static java.lang.String.format;
|
||||||
import static java.lang.System.err;
|
import static java.lang.System.err;
|
||||||
import static java.lang.System.exit;
|
import static java.lang.System.exit;
|
||||||
import static java.lang.System.out;
|
import static java.lang.System.out;
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A command-line client for the Bisq gRPC API.
|
* A command-line client for the Bisq gRPC API.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class CliMain {
|
public class CliMain {
|
||||||
|
|
||||||
private enum Method {
|
private enum Method {
|
||||||
|
getoffers,
|
||||||
|
createpaymentacct,
|
||||||
|
getpaymentaccts,
|
||||||
getversion,
|
getversion,
|
||||||
getbalance,
|
getbalance,
|
||||||
|
getaddressbalance,
|
||||||
|
getfundingaddresses,
|
||||||
lockwallet,
|
lockwallet,
|
||||||
unlockwallet,
|
unlockwallet,
|
||||||
removewalletpassword,
|
removewalletpassword,
|
||||||
@ -131,7 +145,9 @@ public class CliMain {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
var versionService = GetVersionGrpc.newBlockingStub(channel).withCallCredentials(credentials);
|
var versionService = GetVersionGrpc.newBlockingStub(channel).withCallCredentials(credentials);
|
||||||
var walletService = WalletGrpc.newBlockingStub(channel).withCallCredentials(credentials);
|
var offersService = OffersGrpc.newBlockingStub(channel).withCallCredentials(credentials);
|
||||||
|
var paymentAccountsService = PaymentAccountsGrpc.newBlockingStub(channel).withCallCredentials(credentials);
|
||||||
|
var walletsService = WalletsGrpc.newBlockingStub(channel).withCallCredentials(credentials);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch (method) {
|
switch (method) {
|
||||||
@ -143,18 +159,68 @@ public class CliMain {
|
|||||||
}
|
}
|
||||||
case getbalance: {
|
case getbalance: {
|
||||||
var request = GetBalanceRequest.newBuilder().build();
|
var request = GetBalanceRequest.newBuilder().build();
|
||||||
var reply = walletService.getBalance(request);
|
var reply = walletsService.getBalance(request);
|
||||||
var satoshiBalance = reply.getBalance();
|
var btcBalance = formatSatoshis(reply.getBalance());
|
||||||
var satoshiDivisor = new BigDecimal(100000000);
|
|
||||||
var btcFormat = new DecimalFormat("###,##0.00000000");
|
|
||||||
@SuppressWarnings("BigDecimalMethodWithoutRoundingCalled")
|
|
||||||
var btcBalance = btcFormat.format(BigDecimal.valueOf(satoshiBalance).divide(satoshiDivisor));
|
|
||||||
out.println(btcBalance);
|
out.println(btcBalance);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case getaddressbalance: {
|
||||||
|
if (nonOptionArgs.size() < 2)
|
||||||
|
throw new IllegalArgumentException("no address specified");
|
||||||
|
|
||||||
|
var request = GetAddressBalanceRequest.newBuilder()
|
||||||
|
.setAddress(nonOptionArgs.get(1)).build();
|
||||||
|
var reply = walletsService.getAddressBalance(request);
|
||||||
|
out.println(formatAddressBalanceTbl(singletonList(reply.getAddressBalanceInfo())));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case getfundingaddresses: {
|
||||||
|
var request = GetFundingAddressesRequest.newBuilder().build();
|
||||||
|
var reply = walletsService.getFundingAddresses(request);
|
||||||
|
out.println(formatAddressBalanceTbl(reply.getAddressBalanceInfoList()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case getoffers: {
|
||||||
|
if (nonOptionArgs.size() < 3)
|
||||||
|
throw new IllegalArgumentException("incorrect parameter count, expecting direction (buy|sell), currency code");
|
||||||
|
|
||||||
|
var direction = nonOptionArgs.get(1);
|
||||||
|
var fiatCurrency = nonOptionArgs.get(2);
|
||||||
|
|
||||||
|
var request = GetOffersRequest.newBuilder()
|
||||||
|
.setDirection(direction)
|
||||||
|
.setFiatCurrencyCode(fiatCurrency)
|
||||||
|
.build();
|
||||||
|
var reply = offersService.getOffers(request);
|
||||||
|
out.println(formatOfferTable(reply.getOffersList(), fiatCurrency));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case createpaymentacct: {
|
||||||
|
if (nonOptionArgs.size() < 4)
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"incorrect parameter count, expecting account name, account number, currency code");
|
||||||
|
|
||||||
|
var accountName = nonOptionArgs.get(1);
|
||||||
|
var accountNumber = nonOptionArgs.get(2);
|
||||||
|
var fiatCurrencyCode = nonOptionArgs.get(3);
|
||||||
|
|
||||||
|
var request = CreatePaymentAccountRequest.newBuilder()
|
||||||
|
.setAccountName(accountName)
|
||||||
|
.setAccountNumber(accountNumber)
|
||||||
|
.setFiatCurrencyCode(fiatCurrencyCode).build();
|
||||||
|
paymentAccountsService.createPaymentAccount(request);
|
||||||
|
out.println(format("payment account %s saved", accountName));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case getpaymentaccts: {
|
||||||
|
var request = GetPaymentAccountsRequest.newBuilder().build();
|
||||||
|
var reply = paymentAccountsService.getPaymentAccounts(request);
|
||||||
|
out.println(formatPaymentAcctTbl(reply.getPaymentAccountsList()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
case lockwallet: {
|
case lockwallet: {
|
||||||
var request = LockWalletRequest.newBuilder().build();
|
var request = LockWalletRequest.newBuilder().build();
|
||||||
walletService.lockWallet(request);
|
walletsService.lockWallet(request);
|
||||||
out.println("wallet locked");
|
out.println("wallet locked");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -174,7 +240,7 @@ public class CliMain {
|
|||||||
var request = UnlockWalletRequest.newBuilder()
|
var request = UnlockWalletRequest.newBuilder()
|
||||||
.setPassword(nonOptionArgs.get(1))
|
.setPassword(nonOptionArgs.get(1))
|
||||||
.setTimeout(timeout).build();
|
.setTimeout(timeout).build();
|
||||||
walletService.unlockWallet(request);
|
walletsService.unlockWallet(request);
|
||||||
out.println("wallet unlocked");
|
out.println("wallet unlocked");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -183,7 +249,7 @@ public class CliMain {
|
|||||||
throw new IllegalArgumentException("no password specified");
|
throw new IllegalArgumentException("no password specified");
|
||||||
|
|
||||||
var request = RemoveWalletPasswordRequest.newBuilder().setPassword(nonOptionArgs.get(1)).build();
|
var request = RemoveWalletPasswordRequest.newBuilder().setPassword(nonOptionArgs.get(1)).build();
|
||||||
walletService.removeWalletPassword(request);
|
walletsService.removeWalletPassword(request);
|
||||||
out.println("wallet decrypted");
|
out.println("wallet decrypted");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -195,13 +261,13 @@ public class CliMain {
|
|||||||
var hasNewPassword = nonOptionArgs.size() == 3;
|
var hasNewPassword = nonOptionArgs.size() == 3;
|
||||||
if (hasNewPassword)
|
if (hasNewPassword)
|
||||||
requestBuilder.setNewPassword(nonOptionArgs.get(2));
|
requestBuilder.setNewPassword(nonOptionArgs.get(2));
|
||||||
walletService.setWalletPassword(requestBuilder.build());
|
walletsService.setWalletPassword(requestBuilder.build());
|
||||||
out.println("wallet encrypted" + (hasNewPassword ? " with new password" : ""));
|
out.println("wallet encrypted" + (hasNewPassword ? " with new password" : ""));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
throw new RuntimeException(format("unhandled method '%s'", method));
|
throw new RuntimeException(format("unhandled method '%s'", method));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (StatusRuntimeException ex) {
|
} catch (StatusRuntimeException ex) {
|
||||||
// Remove the leading gRPC status code (e.g. "UNKNOWN: ") from the message
|
// Remove the leading gRPC status code (e.g. "UNKNOWN: ") from the message
|
||||||
@ -218,14 +284,19 @@ public class CliMain {
|
|||||||
stream.println();
|
stream.println();
|
||||||
parser.printHelpOn(stream);
|
parser.printHelpOn(stream);
|
||||||
stream.println();
|
stream.println();
|
||||||
stream.format("%-19s%-30s%s%n", "Method", "Params", "Description");
|
stream.format("%-22s%-50s%s%n", "Method", "Params", "Description");
|
||||||
stream.format("%-19s%-30s%s%n", "------", "------", "------------");
|
stream.format("%-22s%-50s%s%n", "------", "------", "------------");
|
||||||
stream.format("%-19s%-30s%s%n", "getversion", "", "Get server version");
|
stream.format("%-22s%-50s%s%n", "getversion", "", "Get server version");
|
||||||
stream.format("%-19s%-30s%s%n", "getbalance", "", "Get server wallet balance");
|
stream.format("%-22s%-50s%s%n", "getbalance", "", "Get server wallet balance");
|
||||||
stream.format("%-19s%-30s%s%n", "lockwallet", "", "Remove wallet password from memory, locking the wallet");
|
stream.format("%-22s%-50s%s%n", "getaddressbalance", "address", "Get server wallet address balance");
|
||||||
stream.format("%-19s%-30s%s%n", "unlockwallet", "password timeout",
|
stream.format("%-22s%-50s%s%n", "getfundingaddresses", "", "Get BTC funding addresses");
|
||||||
|
stream.format("%-22s%-50s%s%n", "getoffers", "buy | sell, fiat currency code", "Get current offers");
|
||||||
|
stream.format("%-22s%-50s%s%n", "createpaymentacct", "account name, account number, currency code", "Create PerfectMoney dummy account");
|
||||||
|
stream.format("%-22s%-50s%s%n", "getpaymentaccts", "", "Get user payment accounts");
|
||||||
|
stream.format("%-22s%-50s%s%n", "lockwallet", "", "Remove wallet password from memory, locking the wallet");
|
||||||
|
stream.format("%-22s%-50s%s%n", "unlockwallet", "password timeout",
|
||||||
"Store wallet password in memory for timeout seconds");
|
"Store wallet password in memory for timeout seconds");
|
||||||
stream.format("%-19s%-30s%s%n", "setwalletpassword", "password [newpassword]",
|
stream.format("%-22s%-50s%s%n", "setwalletpassword", "password [newpassword]",
|
||||||
"Encrypt wallet with password, or set new password on encrypted wallet");
|
"Encrypt wallet with password, or set new password on encrypted wallet");
|
||||||
stream.println();
|
stream.println();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
|
47
cli/src/main/java/bisq/cli/CurrencyFormat.java
Normal file
47
cli/src/main/java/bisq/cli/CurrencyFormat.java
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package bisq.cli;
|
||||||
|
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
import java.text.NumberFormat;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
class CurrencyFormat {
|
||||||
|
|
||||||
|
private static final NumberFormat NUMBER_FORMAT = NumberFormat.getInstance(Locale.US);
|
||||||
|
|
||||||
|
static final BigDecimal SATOSHI_DIVISOR = new BigDecimal(100000000);
|
||||||
|
static final DecimalFormat BTC_FORMAT = new DecimalFormat("###,##0.00000000");
|
||||||
|
|
||||||
|
@SuppressWarnings("BigDecimalMethodWithoutRoundingCalled")
|
||||||
|
static final String formatSatoshis(long sats) {
|
||||||
|
return BTC_FORMAT.format(BigDecimal.valueOf(sats).divide(SATOSHI_DIVISOR));
|
||||||
|
}
|
||||||
|
|
||||||
|
static String formatAmountRange(long minAmount, long amount) {
|
||||||
|
return minAmount != amount
|
||||||
|
? formatSatoshis(minAmount) + " - " + formatSatoshis(amount)
|
||||||
|
: formatSatoshis(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String formatVolumeRange(long minVolume, long volume) {
|
||||||
|
return minVolume != volume
|
||||||
|
? formatOfferVolume(minVolume) + " - " + formatOfferVolume(volume)
|
||||||
|
: formatOfferVolume(volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String formatOfferPrice(long price) {
|
||||||
|
NUMBER_FORMAT.setMaximumFractionDigits(4);
|
||||||
|
NUMBER_FORMAT.setMinimumFractionDigits(4);
|
||||||
|
NUMBER_FORMAT.setRoundingMode(RoundingMode.UNNECESSARY);
|
||||||
|
return NUMBER_FORMAT.format((double) price / 10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String formatOfferVolume(long volume) {
|
||||||
|
NUMBER_FORMAT.setMaximumFractionDigits(0);
|
||||||
|
NUMBER_FORMAT.setRoundingMode(RoundingMode.UNNECESSARY);
|
||||||
|
return NUMBER_FORMAT.format((double) volume / 10000);
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* 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.cli;
|
package bisq.cli;
|
||||||
|
|
||||||
import io.grpc.CallCredentials;
|
import io.grpc.CallCredentials;
|
||||||
|
144
cli/src/main/java/bisq/cli/TableFormat.java
Normal file
144
cli/src/main/java/bisq/cli/TableFormat.java
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
package bisq.cli;
|
||||||
|
|
||||||
|
import bisq.proto.grpc.AddressBalanceInfo;
|
||||||
|
import bisq.proto.grpc.OfferInfo;
|
||||||
|
|
||||||
|
import protobuf.PaymentAccount;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static bisq.cli.CurrencyFormat.formatAmountRange;
|
||||||
|
import static bisq.cli.CurrencyFormat.formatOfferPrice;
|
||||||
|
import static bisq.cli.CurrencyFormat.formatSatoshis;
|
||||||
|
import static bisq.cli.CurrencyFormat.formatVolumeRange;
|
||||||
|
import static com.google.common.base.Strings.padEnd;
|
||||||
|
import static com.google.common.base.Strings.padStart;
|
||||||
|
import static java.lang.String.format;
|
||||||
|
import static java.util.Collections.max;
|
||||||
|
import static java.util.Comparator.comparing;
|
||||||
|
import static java.util.TimeZone.getTimeZone;
|
||||||
|
|
||||||
|
class TableFormat {
|
||||||
|
|
||||||
|
private static final TimeZone TZ_UTC = getTimeZone("UTC");
|
||||||
|
private static final SimpleDateFormat DATE_FORMAT_ISO_8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
|
||||||
|
|
||||||
|
// For inserting 2 spaces between column headers.
|
||||||
|
private static final String COL_HEADER_DELIMITER = " ";
|
||||||
|
|
||||||
|
// Table column header format specs, right padded with two spaces. In some cases
|
||||||
|
// such as COL_HEADER_CREATION_DATE, COL_HEADER_VOLUME and COL_HEADER_UUID, the
|
||||||
|
// expected max data string length is accounted for. In others, the column header length
|
||||||
|
// are expected to be greater than any column value length.
|
||||||
|
private static final String COL_HEADER_ADDRESS = padEnd("Address", 34, ' ');
|
||||||
|
private static final String COL_HEADER_AMOUNT = padEnd("BTC(min - max)", 24, ' ');
|
||||||
|
private static final String COL_HEADER_BALANCE = padStart("Balance", 12, ' ');
|
||||||
|
private static final String COL_HEADER_CONFIRMATIONS = "Confirmations";
|
||||||
|
private static final String COL_HEADER_CREATION_DATE = padEnd("Creation Date (UTC)", 20, ' ');
|
||||||
|
private static final String COL_HEADER_CURRENCY = "Currency";
|
||||||
|
private static final String COL_HEADER_DIRECTION = "Buy/Sell"; // TODO "Take Offer to
|
||||||
|
private static final String COL_HEADER_NAME = "Name";
|
||||||
|
private static final String COL_HEADER_PAYMENT_METHOD = "Payment Method";
|
||||||
|
private static final String COL_HEADER_PRICE = "Price in %-3s for 1 BTC";
|
||||||
|
private static final String COL_HEADER_VOLUME = padEnd("%-3s(min - max)", 15, ' ');
|
||||||
|
private static final String COL_HEADER_UUID = padEnd("ID", 52, ' ');
|
||||||
|
|
||||||
|
static String formatAddressBalanceTbl(List<AddressBalanceInfo> addressBalanceInfo) {
|
||||||
|
String headerLine = (COL_HEADER_ADDRESS + COL_HEADER_DELIMITER
|
||||||
|
+ COL_HEADER_BALANCE + COL_HEADER_DELIMITER
|
||||||
|
+ COL_HEADER_CONFIRMATIONS + COL_HEADER_DELIMITER + "\n");
|
||||||
|
String colDataFormat = "%-" + COL_HEADER_ADDRESS.length() + "s" // left justify
|
||||||
|
+ " %" + COL_HEADER_BALANCE.length() + "s" // right justify
|
||||||
|
+ " %" + COL_HEADER_CONFIRMATIONS.length() + "d"; // right justify
|
||||||
|
return headerLine
|
||||||
|
+ addressBalanceInfo.stream()
|
||||||
|
.map(info -> format(colDataFormat,
|
||||||
|
info.getAddress(),
|
||||||
|
formatSatoshis(info.getBalance()),
|
||||||
|
info.getNumConfirmations()))
|
||||||
|
.collect(Collectors.joining("\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static String formatOfferTable(List<OfferInfo> offerInfo, String fiatCurrency) {
|
||||||
|
|
||||||
|
// Some column values might be longer than header, so we need to calculated them.
|
||||||
|
int paymentMethodColWidth = getLengthOfLongestColumn(
|
||||||
|
COL_HEADER_PAYMENT_METHOD.length(),
|
||||||
|
offerInfo.stream()
|
||||||
|
.map(OfferInfo::getPaymentMethodShortName)
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
|
||||||
|
String headersFormat = COL_HEADER_DIRECTION + COL_HEADER_DELIMITER
|
||||||
|
+ COL_HEADER_PRICE + COL_HEADER_DELIMITER // includes %s -> fiatCurrency
|
||||||
|
+ COL_HEADER_AMOUNT + COL_HEADER_DELIMITER
|
||||||
|
+ COL_HEADER_VOLUME + COL_HEADER_DELIMITER // includes %s -> fiatCurrency
|
||||||
|
+ padEnd(COL_HEADER_PAYMENT_METHOD, paymentMethodColWidth, ' ') + COL_HEADER_DELIMITER
|
||||||
|
+ COL_HEADER_CREATION_DATE + COL_HEADER_DELIMITER
|
||||||
|
+ COL_HEADER_UUID.trim() + "%n";
|
||||||
|
String headerLine = format(headersFormat, fiatCurrency, fiatCurrency);
|
||||||
|
|
||||||
|
String colDataFormat = "%-" + (COL_HEADER_DIRECTION.length() + COL_HEADER_DELIMITER.length()) + "s" // left
|
||||||
|
+ "%" + (COL_HEADER_PRICE.length() - 1) + "s" // rt justify to end of hdr
|
||||||
|
+ " %-" + (COL_HEADER_AMOUNT.length() - 1) + "s" // left justify
|
||||||
|
+ " %" + COL_HEADER_VOLUME.length() + "s" // right justify
|
||||||
|
+ " %-" + paymentMethodColWidth + "s" // left justify
|
||||||
|
+ " %-" + (COL_HEADER_CREATION_DATE.length()) + "s" // left justify
|
||||||
|
+ " %-" + COL_HEADER_UUID.length() + "s";
|
||||||
|
return headerLine
|
||||||
|
+ offerInfo.stream()
|
||||||
|
.map(o -> format(colDataFormat,
|
||||||
|
o.getDirection(),
|
||||||
|
formatOfferPrice(o.getPrice()),
|
||||||
|
formatAmountRange(o.getMinAmount(), o.getAmount()),
|
||||||
|
formatVolumeRange(o.getMinVolume(), o.getVolume()),
|
||||||
|
o.getPaymentMethodShortName(),
|
||||||
|
formatTimestamp(o.getDate()),
|
||||||
|
o.getId()))
|
||||||
|
.collect(Collectors.joining("\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static String formatPaymentAcctTbl(List<PaymentAccount> paymentAccounts) {
|
||||||
|
// Some column values might be longer than header, so we need to calculated them.
|
||||||
|
int nameColWidth = getLengthOfLongestColumn(
|
||||||
|
COL_HEADER_NAME.length(),
|
||||||
|
paymentAccounts.stream().map(PaymentAccount::getAccountName)
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
int paymentMethodColWidth = getLengthOfLongestColumn(
|
||||||
|
COL_HEADER_PAYMENT_METHOD.length(),
|
||||||
|
paymentAccounts.stream().map(a -> a.getPaymentMethod().getId())
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
|
||||||
|
String headerLine = padEnd(COL_HEADER_NAME, nameColWidth, ' ') + COL_HEADER_DELIMITER
|
||||||
|
+ COL_HEADER_CURRENCY + COL_HEADER_DELIMITER
|
||||||
|
+ padEnd(COL_HEADER_PAYMENT_METHOD, paymentMethodColWidth, ' ') + COL_HEADER_DELIMITER
|
||||||
|
+ COL_HEADER_UUID + COL_HEADER_DELIMITER + "\n";
|
||||||
|
String colDataFormat = "%-" + nameColWidth + "s" // left justify
|
||||||
|
+ " %" + COL_HEADER_CURRENCY.length() + "s" // right justify
|
||||||
|
+ " %-" + paymentMethodColWidth + "s" // left justify
|
||||||
|
+ " %-" + COL_HEADER_UUID.length() + "s"; // left justify
|
||||||
|
return headerLine
|
||||||
|
+ paymentAccounts.stream()
|
||||||
|
.map(a -> format(colDataFormat,
|
||||||
|
a.getAccountName(),
|
||||||
|
a.getSelectedTradeCurrency().getCode(),
|
||||||
|
a.getPaymentMethod().getId(),
|
||||||
|
a.getId()))
|
||||||
|
.collect(Collectors.joining("\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return length of the longest string value, or the header.len, whichever is greater.
|
||||||
|
private static int getLengthOfLongestColumn(int headerLength, List<String> strings) {
|
||||||
|
int longest = max(strings, comparing(String::length)).length();
|
||||||
|
return Math.max(longest, headerLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String formatTimestamp(long timestamp) {
|
||||||
|
DATE_FORMAT_ISO_8601.setTimeZone(TZ_UTC);
|
||||||
|
return DATE_FORMAT_ISO_8601.format(new Date(timestamp));
|
||||||
|
}
|
||||||
|
}
|
39
cli/src/test/java/bisq/cli/GetOffersSmokeTest.java
Normal file
39
cli/src/test/java/bisq/cli/GetOffersSmokeTest.java
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package bisq.cli;
|
||||||
|
|
||||||
|
import static java.lang.System.out;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Smoke tests for getoffers method. Useful for examining the format of the console output.
|
||||||
|
|
||||||
|
Prerequisites:
|
||||||
|
|
||||||
|
- Run `./bisq-daemon --apiPassword=xyz --appDataDir=$TESTDIR`
|
||||||
|
|
||||||
|
This can be run on mainnet.
|
||||||
|
*/
|
||||||
|
public class GetOffersSmokeTest {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
out.println(">>> getoffers buy usd");
|
||||||
|
CliMain.main(new String[]{"--password=xyz", "getoffers", "buy", "usd"});
|
||||||
|
out.println(">>> getoffers sell usd");
|
||||||
|
CliMain.main(new String[]{"--password=xyz", "getoffers", "sell", "usd"});
|
||||||
|
|
||||||
|
out.println(">>> getoffers buy eur");
|
||||||
|
CliMain.main(new String[]{"--password=xyz", "getoffers", "buy", "eur"});
|
||||||
|
out.println(">>> getoffers sell eur");
|
||||||
|
CliMain.main(new String[]{"--password=xyz", "getoffers", "sell", "eur"});
|
||||||
|
|
||||||
|
out.println(">>> getoffers buy gbp");
|
||||||
|
CliMain.main(new String[]{"--password=xyz", "getoffers", "buy", "gbp"});
|
||||||
|
out.println(">>> getoffers sell gbp");
|
||||||
|
CliMain.main(new String[]{"--password=xyz", "getoffers", "sell", "gbp"});
|
||||||
|
|
||||||
|
out.println(">>> getoffers buy brl");
|
||||||
|
CliMain.main(new String[]{"--password=xyz", "getoffers", "buy", "brl"});
|
||||||
|
out.println(">>> getoffers sell brl");
|
||||||
|
CliMain.main(new String[]{"--password=xyz", "getoffers", "sell", "brl"});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
150
cli/test.sh
150
cli/test.sh
@ -48,28 +48,168 @@
|
|||||||
run ./bisq-cli --password="xyz" getversion
|
run ./bisq-cli --password="xyz" getversion
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
echo "actual output: $output" >&2
|
echo "actual output: $output" >&2
|
||||||
[ "$output" = "1.3.2" ]
|
[ "$output" = "1.3.4" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "test getversion" {
|
@test "test getversion" {
|
||||||
run ./bisq-cli --password=xyz getversion
|
run ./bisq-cli --password=xyz getversion
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
echo "actual output: $output" >&2
|
echo "actual output: $output" >&2
|
||||||
[ "$output" = "1.3.2" ]
|
[ "$output" = "1.3.4" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "test getbalance (available & unlocked wallet with 0 btc balance)" {
|
@test "test setwalletpassword \"a b c\"" {
|
||||||
|
run ./bisq-cli --password=xyz setwalletpassword "a b c"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
echo "actual output: $output" >&2
|
||||||
|
[ "$output" = "wallet encrypted" ]
|
||||||
|
sleep 1
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "test unlockwallet without password & timeout args" {
|
||||||
|
run ./bisq-cli --password=xyz unlockwallet
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
echo "actual output: $output" >&2
|
||||||
|
[ "$output" = "Error: no password specified" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "test unlockwallet without timeout arg" {
|
||||||
|
run ./bisq-cli --password=xyz unlockwallet "a b c"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
echo "actual output: $output" >&2
|
||||||
|
[ "$output" = "Error: no unlock timeout specified" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@test "test unlockwallet \"a b c\" 8" {
|
||||||
|
run ./bisq-cli --password=xyz unlockwallet "a b c" 8
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
echo "actual output: $output" >&2
|
||||||
|
[ "$output" = "wallet unlocked" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "test getbalance while wallet unlocked for 8s" {
|
||||||
|
run ./bisq-cli --password=xyz getbalance
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
echo "actual output: $output" >&2
|
||||||
|
[ "$output" = "0.00000000" ]
|
||||||
|
sleep 8
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "test unlockwallet \"a b c\" 6" {
|
||||||
|
run ./bisq-cli --password=xyz unlockwallet "a b c" 6
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
echo "actual output: $output" >&2
|
||||||
|
[ "$output" = "wallet unlocked" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "test lockwallet before unlockwallet timeout=6s expires" {
|
||||||
|
run ./bisq-cli --password=xyz lockwallet
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
echo "actual output: $output" >&2
|
||||||
|
[ "$output" = "wallet locked" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "test setwalletpassword incorrect old pwd error" {
|
||||||
|
run ./bisq-cli --password=xyz setwalletpassword "z z z" "d e f"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
echo "actual output: $output" >&2
|
||||||
|
[ "$output" = "Error: incorrect old password" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "test setwalletpassword oldpwd newpwd" {
|
||||||
|
run ./bisq-cli --password=xyz setwalletpassword "a b c" "d e f"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
echo "actual output: $output" >&2
|
||||||
|
[ "$output" = "wallet encrypted with new password" ]
|
||||||
|
sleep 1
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "test getbalance wallet locked error" {
|
||||||
|
run ./bisq-cli --password=xyz getbalance
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
echo "actual output: $output" >&2
|
||||||
|
[ "$output" = "Error: wallet is locked" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "test removewalletpassword" {
|
||||||
|
run ./bisq-cli --password=xyz removewalletpassword "d e f"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
echo "actual output: $output" >&2
|
||||||
|
[ "$output" = "wallet decrypted" ]
|
||||||
|
sleep 1
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "test getbalance when wallet available & unlocked with 0 btc balance" {
|
||||||
run ./bisq-cli --password=xyz getbalance
|
run ./bisq-cli --password=xyz getbalance
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
echo "actual output: $output" >&2
|
echo "actual output: $output" >&2
|
||||||
[ "$output" = "0.00000000" ]
|
[ "$output" = "0.00000000" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "test getfundingaddresses" {
|
||||||
|
run ./bisq-cli --password=xyz getfundingaddresses
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "test getaddressbalance missing address argument" {
|
||||||
|
run ./bisq-cli --password=xyz getaddressbalance
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
echo "actual output: $output" >&2
|
||||||
|
[ "$output" = "Error: no address specified" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "test getaddressbalance bogus address argument" {
|
||||||
|
run ./bisq-cli --password=xyz getaddressbalance bogus
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
echo "actual output: $output" >&2
|
||||||
|
[ "$output" = "Error: address bogus not found in wallet" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "test createpaymentacct PerfectMoneyDummy (missing nbr, ccy params)" {
|
||||||
|
run ./bisq-cli --password=xyz createpaymentacct PerfectMoneyDummy
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
echo "actual output: $output" >&2
|
||||||
|
[ "$output" = "Error: incorrect parameter count, expecting account name, account number, currency code" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "test createpaymentacct PerfectMoneyDummy 0123456789 USD" {
|
||||||
|
run ./bisq-cli --password=xyz createpaymentacct PerfectMoneyDummy 0123456789 USD
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "test getpaymentaccts" {
|
||||||
|
run ./bisq-cli --password=xyz getpaymentaccts
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "test getoffers missing direction argument" {
|
||||||
|
run ./bisq-cli --password=xyz getoffers
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
echo "actual output: $output" >&2
|
||||||
|
[ "$output" = "Error: incorrect parameter count, expecting direction (buy|sell), currency code" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "test getoffers buy eur check return status" {
|
||||||
|
run ./bisq-cli --password=xyz getoffers buy eur
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "test getoffers buy eur check return status" {
|
||||||
|
run ./bisq-cli --password=xyz getoffers buy eur
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "test getoffers sell gbp check return status" {
|
||||||
|
run ./bisq-cli --password=xyz getoffers sell gbp
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
@test "test help displayed on stderr if no options or arguments" {
|
@test "test help displayed on stderr if no options or arguments" {
|
||||||
run ./bisq-cli
|
run ./bisq-cli
|
||||||
[ "$status" -eq 1 ]
|
[ "$status" -eq 1 ]
|
||||||
[ "${lines[0]}" = "Bisq RPC Client" ]
|
[ "${lines[0]}" = "Bisq RPC Client" ]
|
||||||
[ "${lines[1]}" = "Usage: bisq-cli [options] <method>" ]
|
[ "${lines[1]}" = "Usage: bisq-cli [options] <method> [params]" ]
|
||||||
# TODO add asserts after help text is modified for new endpoints
|
# TODO add asserts after help text is modified for new endpoints
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,6 +217,6 @@
|
|||||||
run ./bisq-cli --help
|
run ./bisq-cli --help
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
[ "${lines[0]}" = "Bisq RPC Client" ]
|
[ "${lines[0]}" = "Bisq RPC Client" ]
|
||||||
[ "${lines[1]}" = "Usage: bisq-cli [options] <method>" ]
|
[ "${lines[1]}" = "Usage: bisq-cli [options] <method> [params]" ]
|
||||||
# TODO add asserts after help text is modified for new endpoints
|
# TODO add asserts after help text is modified for new endpoints
|
||||||
}
|
}
|
||||||
|
@ -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
|
// 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
|
// Therefore all sub versions start again with 1
|
||||||
// We use semantic versioning with major, minor and patch
|
// We use semantic versioning with major, minor and patch
|
||||||
public static final String VERSION = "1.3.4";
|
public static final String VERSION = "1.3.5";
|
||||||
|
|
||||||
public static int getMajorVersion(String version) {
|
public static int getMajorVersion(String version) {
|
||||||
return getSubVersion(version, 0);
|
return getSubVersion(version, 0);
|
||||||
|
@ -262,6 +262,12 @@ public class SignedWitnessService {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void selfSignAccountAgeWitness(AccountAgeWitness accountAgeWitness) throws CryptoException {
|
||||||
|
log.info("Sign own accountAgeWitness {}", accountAgeWitness);
|
||||||
|
signAccountAgeWitness(MINIMUM_TRADE_AMOUNT_FOR_SIGNING, accountAgeWitness,
|
||||||
|
keyRing.getSignatureKeyPair().getPublic());
|
||||||
|
}
|
||||||
|
|
||||||
// Any peer can sign with DSA key
|
// Any peer can sign with DSA key
|
||||||
public void signAccountAgeWitness(Coin tradeAmount,
|
public void signAccountAgeWitness(Coin tradeAmount,
|
||||||
AccountAgeWitness accountAgeWitness,
|
AccountAgeWitness accountAgeWitness,
|
||||||
|
@ -185,17 +185,23 @@ public class AccountAgeWitnessService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (p2PService.isBootstrapped()) {
|
if (p2PService.isBootstrapped()) {
|
||||||
republishAllFiatAccounts();
|
onBootStrapped();
|
||||||
} else {
|
} else {
|
||||||
p2PService.addP2PServiceListener(new BootstrapListener() {
|
p2PService.addP2PServiceListener(new BootstrapListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onUpdatedDataReceived() {
|
public void onUpdatedDataReceived() {
|
||||||
republishAllFiatAccounts();
|
onBootStrapped();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onBootStrapped() {
|
||||||
|
republishAllFiatAccounts();
|
||||||
|
signSameNameAccounts();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// At startup we re-publish the witness data of all fiat accounts to ensure we got our data well distributed.
|
// At startup we re-publish the witness data of all fiat accounts to ensure we got our data well distributed.
|
||||||
private void republishAllFiatAccounts() {
|
private void republishAllFiatAccounts() {
|
||||||
if (user.getPaymentAccounts() != null)
|
if (user.getPaymentAccounts() != null)
|
||||||
@ -814,6 +820,30 @@ public class AccountAgeWitnessService {
|
|||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void signSameNameAccounts() {
|
||||||
|
// Collect accounts that have ownerId to sign unsigned accounts with the same ownderId
|
||||||
|
var signerAccounts = Objects.requireNonNull(user.getPaymentAccounts()).stream()
|
||||||
|
.filter(account -> account.getOwnerId() != null &&
|
||||||
|
accountIsSigner(getMyWitness(account.getPaymentAccountPayload())))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
var unsignedAccounts = user.getPaymentAccounts().stream()
|
||||||
|
.filter(account -> account.getOwnerId() != null &&
|
||||||
|
!signedWitnessService.isSignedAccountAgeWitness(
|
||||||
|
getMyWitness(account.getPaymentAccountPayload())))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
signerAccounts.forEach(signer -> unsignedAccounts.forEach(unsigned -> {
|
||||||
|
if (signer.getOwnerId().equals(unsigned.getOwnerId())) {
|
||||||
|
try {
|
||||||
|
signedWitnessService.selfSignAccountAgeWitness(
|
||||||
|
getMyWitness(unsigned.getPaymentAccountPayload()));
|
||||||
|
} catch (CryptoException e) {
|
||||||
|
log.warn("Self signing failed, exception {}", e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
public Set<SignedWitness> getUnsignedSignerPubKeys() {
|
public Set<SignedWitness> getUnsignedSignerPubKeys() {
|
||||||
return signedWitnessService.getUnsignedSignerPubKeys();
|
return signedWitnessService.getUnsignedSignerPubKeys();
|
||||||
}
|
}
|
||||||
|
@ -75,9 +75,10 @@ public class BtcNodes {
|
|||||||
new BtcNode("btc.bisq.cc", "4nnuyxm5k5tlyjq3.onion", "167.71.168.194", BtcNode.DEFAULT_PORT, "@m52go"),
|
new BtcNode("btc.bisq.cc", "4nnuyxm5k5tlyjq3.onion", "167.71.168.194", BtcNode.DEFAULT_PORT, "@m52go"),
|
||||||
|
|
||||||
// wiz
|
// wiz
|
||||||
new BtcNode("node100.wiz.network", "m3yqzythryowgedc.onion", "103.99.168.100", BtcNode.DEFAULT_PORT, "@wiz"),
|
new BtcNode("node100.hnl.wiz.biz", "m3yqzythryowgedc.onion", "103.99.168.100", BtcNode.DEFAULT_PORT, "@wiz"),
|
||||||
new BtcNode("node130.wiz.network", "22tg6ufbwz6o3l2u.onion", "103.99.168.130", BtcNode.DEFAULT_PORT, "@wiz"),
|
new BtcNode("node140.hnl.wiz.biz", "jiuuuislm7ooesic.onion", "103.99.168.140", BtcNode.DEFAULT_PORT, "@wiz"),
|
||||||
new BtcNode("node140.wiz.network", "jiuuuislm7ooesic.onion", "103.99.168.140", BtcNode.DEFAULT_PORT, "@wiz"),
|
new BtcNode("node210.fmt.wiz.biz", "orsy2v63ecrmdj55.onion", "103.99.170.210", BtcNode.DEFAULT_PORT, "@wiz"),
|
||||||
|
new BtcNode("node220.fmt.wiz.biz", "z6mbqq7llxlrn4kq.onion", "103.99.170.220", BtcNode.DEFAULT_PORT, "@wiz"),
|
||||||
|
|
||||||
// Rob Kaandorp
|
// Rob Kaandorp
|
||||||
new BtcNode(null, "2pj2o2mrawj7yotg.onion", null, BtcNode.DEFAULT_PORT, "@robkaandorp") // cannot provide IP because no static IP
|
new BtcNode(null, "2pj2o2mrawj7yotg.onion", null, BtcNode.DEFAULT_PORT, "@robkaandorp") // cannot provide IP because no static IP
|
||||||
|
@ -105,6 +105,10 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private final List<String> bannedSignerPubKeys;
|
private final List<String> bannedSignerPubKeys;
|
||||||
|
|
||||||
|
// added in v1.3.2
|
||||||
|
@Nullable
|
||||||
|
private final List<String> btcFeeReceiverAddresses;
|
||||||
|
|
||||||
public Filter(List<String> bannedOfferIds,
|
public Filter(List<String> bannedOfferIds,
|
||||||
List<String> bannedNodeAddress,
|
List<String> bannedNodeAddress,
|
||||||
List<PaymentAccountFilter> bannedPaymentAccounts,
|
List<PaymentAccountFilter> bannedPaymentAccounts,
|
||||||
@ -120,7 +124,8 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload {
|
|||||||
@Nullable String disableTradeBelowVersion,
|
@Nullable String disableTradeBelowVersion,
|
||||||
@Nullable List<String> mediators,
|
@Nullable List<String> mediators,
|
||||||
@Nullable List<String> refundAgents,
|
@Nullable List<String> refundAgents,
|
||||||
@Nullable List<String> bannedSignerPubKeys) {
|
@Nullable List<String> bannedSignerPubKeys,
|
||||||
|
@Nullable List<String> btcFeeReceiverAddresses) {
|
||||||
this.bannedOfferIds = bannedOfferIds;
|
this.bannedOfferIds = bannedOfferIds;
|
||||||
this.bannedNodeAddress = bannedNodeAddress;
|
this.bannedNodeAddress = bannedNodeAddress;
|
||||||
this.bannedPaymentAccounts = bannedPaymentAccounts;
|
this.bannedPaymentAccounts = bannedPaymentAccounts;
|
||||||
@ -137,6 +142,7 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload {
|
|||||||
this.mediators = mediators;
|
this.mediators = mediators;
|
||||||
this.refundAgents = refundAgents;
|
this.refundAgents = refundAgents;
|
||||||
this.bannedSignerPubKeys = bannedSignerPubKeys;
|
this.bannedSignerPubKeys = bannedSignerPubKeys;
|
||||||
|
this.btcFeeReceiverAddresses = btcFeeReceiverAddresses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -163,7 +169,8 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload {
|
|||||||
@Nullable Map<String, String> extraDataMap,
|
@Nullable Map<String, String> extraDataMap,
|
||||||
@Nullable List<String> mediators,
|
@Nullable List<String> mediators,
|
||||||
@Nullable List<String> refundAgents,
|
@Nullable List<String> refundAgents,
|
||||||
@Nullable List<String> bannedSignerPubKeys) {
|
@Nullable List<String> bannedSignerPubKeys,
|
||||||
|
@Nullable List<String> btcFeeReceiverAddresses) {
|
||||||
this(bannedOfferIds,
|
this(bannedOfferIds,
|
||||||
bannedNodeAddress,
|
bannedNodeAddress,
|
||||||
bannedPaymentAccounts,
|
bannedPaymentAccounts,
|
||||||
@ -179,7 +186,8 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload {
|
|||||||
disableTradeBelowVersion,
|
disableTradeBelowVersion,
|
||||||
mediators,
|
mediators,
|
||||||
refundAgents,
|
refundAgents,
|
||||||
bannedSignerPubKeys);
|
bannedSignerPubKeys,
|
||||||
|
btcFeeReceiverAddresses);
|
||||||
this.signatureAsBase64 = signatureAsBase64;
|
this.signatureAsBase64 = signatureAsBase64;
|
||||||
this.ownerPubKeyBytes = ownerPubKeyBytes;
|
this.ownerPubKeyBytes = ownerPubKeyBytes;
|
||||||
this.extraDataMap = ExtraDataMapValidator.getValidatedExtraDataMap(extraDataMap);
|
this.extraDataMap = ExtraDataMapValidator.getValidatedExtraDataMap(extraDataMap);
|
||||||
@ -215,6 +223,7 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload {
|
|||||||
Optional.ofNullable(mediators).ifPresent(builder::addAllMediators);
|
Optional.ofNullable(mediators).ifPresent(builder::addAllMediators);
|
||||||
Optional.ofNullable(refundAgents).ifPresent(builder::addAllRefundAgents);
|
Optional.ofNullable(refundAgents).ifPresent(builder::addAllRefundAgents);
|
||||||
Optional.ofNullable(bannedSignerPubKeys).ifPresent(builder::addAllBannedSignerPubKeys);
|
Optional.ofNullable(bannedSignerPubKeys).ifPresent(builder::addAllBannedSignerPubKeys);
|
||||||
|
Optional.ofNullable(btcFeeReceiverAddresses).ifPresent(builder::addAllBtcFeeReceiverAddresses);
|
||||||
|
|
||||||
return protobuf.StoragePayload.newBuilder().setFilter(builder).build();
|
return protobuf.StoragePayload.newBuilder().setFilter(builder).build();
|
||||||
}
|
}
|
||||||
@ -241,7 +250,9 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload {
|
|||||||
CollectionUtils.isEmpty(proto.getMediatorsList()) ? null : new ArrayList<>(proto.getMediatorsList()),
|
CollectionUtils.isEmpty(proto.getMediatorsList()) ? null : new ArrayList<>(proto.getMediatorsList()),
|
||||||
CollectionUtils.isEmpty(proto.getRefundAgentsList()) ? null : new ArrayList<>(proto.getRefundAgentsList()),
|
CollectionUtils.isEmpty(proto.getRefundAgentsList()) ? null : new ArrayList<>(proto.getRefundAgentsList()),
|
||||||
CollectionUtils.isEmpty(proto.getBannedSignerPubKeysList()) ?
|
CollectionUtils.isEmpty(proto.getBannedSignerPubKeysList()) ?
|
||||||
null : new ArrayList<>(proto.getBannedSignerPubKeysList()));
|
null : new ArrayList<>(proto.getBannedSignerPubKeysList()),
|
||||||
|
CollectionUtils.isEmpty(proto.getBtcFeeReceiverAddressesList()) ? null :
|
||||||
|
new ArrayList<>(proto.getBtcFeeReceiverAddressesList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -281,6 +292,7 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload {
|
|||||||
",\n mediators=" + mediators +
|
",\n mediators=" + mediators +
|
||||||
",\n refundAgents=" + refundAgents +
|
",\n refundAgents=" + refundAgents +
|
||||||
",\n bannedSignerPubKeys=" + bannedSignerPubKeys +
|
",\n bannedSignerPubKeys=" + bannedSignerPubKeys +
|
||||||
|
",\n btcFeeReceiverAddresses=" + btcFeeReceiverAddresses +
|
||||||
"\n}";
|
"\n}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
package bisq.core.filter;
|
package bisq.core.filter;
|
||||||
|
|
||||||
import bisq.core.account.witness.AccountAgeWitness;
|
|
||||||
import bisq.core.btc.nodes.BtcNodes;
|
import bisq.core.btc.nodes.BtcNodes;
|
||||||
import bisq.core.payment.payload.PaymentAccountPayload;
|
import bisq.core.payment.payload.PaymentAccountPayload;
|
||||||
import bisq.core.payment.payload.PaymentMethod;
|
import bisq.core.payment.payload.PaymentMethod;
|
||||||
@ -153,7 +152,7 @@ public class FilterManager {
|
|||||||
protectedStorageEntries.forEach(protectedStorageEntry -> {
|
protectedStorageEntries.forEach(protectedStorageEntry -> {
|
||||||
if (protectedStorageEntry.getProtectedStoragePayload() instanceof Filter) {
|
if (protectedStorageEntry.getProtectedStoragePayload() instanceof Filter) {
|
||||||
Filter filter = (Filter) protectedStorageEntry.getProtectedStoragePayload();
|
Filter filter = (Filter) protectedStorageEntry.getProtectedStoragePayload();
|
||||||
if (verifySignature(filter))
|
if (verifySignature(filter) && getFilter().equals(filter))
|
||||||
resetFilters();
|
resetFilters();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -17,17 +17,14 @@
|
|||||||
|
|
||||||
package bisq.core.grpc;
|
package bisq.core.grpc;
|
||||||
|
|
||||||
|
import bisq.core.grpc.model.AddressBalanceInfo;
|
||||||
import bisq.core.monetary.Price;
|
import bisq.core.monetary.Price;
|
||||||
import bisq.core.offer.CreateOfferService;
|
|
||||||
import bisq.core.offer.Offer;
|
import bisq.core.offer.Offer;
|
||||||
import bisq.core.offer.OfferBookService;
|
|
||||||
import bisq.core.offer.OfferPayload;
|
import bisq.core.offer.OfferPayload;
|
||||||
import bisq.core.offer.OpenOfferManager;
|
|
||||||
import bisq.core.payment.PaymentAccount;
|
import bisq.core.payment.PaymentAccount;
|
||||||
import bisq.core.trade.handlers.TransactionResultHandler;
|
import bisq.core.trade.handlers.TransactionResultHandler;
|
||||||
import bisq.core.trade.statistics.TradeStatistics2;
|
import bisq.core.trade.statistics.TradeStatistics2;
|
||||||
import bisq.core.trade.statistics.TradeStatisticsManager;
|
import bisq.core.trade.statistics.TradeStatisticsManager;
|
||||||
import bisq.core.user.User;
|
|
||||||
|
|
||||||
import bisq.common.app.Version;
|
import bisq.common.app.Version;
|
||||||
|
|
||||||
@ -47,61 +44,70 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class CoreApi {
|
public class CoreApi {
|
||||||
private final OfferBookService offerBookService;
|
|
||||||
|
private final CoreOffersService coreOffersService;
|
||||||
|
private final CorePaymentAccountsService paymentAccountsService;
|
||||||
|
private final CoreWalletsService walletsService;
|
||||||
private final TradeStatisticsManager tradeStatisticsManager;
|
private final TradeStatisticsManager tradeStatisticsManager;
|
||||||
private final CreateOfferService createOfferService;
|
|
||||||
private final OpenOfferManager openOfferManager;
|
|
||||||
private final User user;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public CoreApi(OfferBookService offerBookService,
|
public CoreApi(CoreOffersService coreOffersService,
|
||||||
TradeStatisticsManager tradeStatisticsManager,
|
CorePaymentAccountsService paymentAccountsService,
|
||||||
CreateOfferService createOfferService,
|
CoreWalletsService walletsService,
|
||||||
OpenOfferManager openOfferManager,
|
TradeStatisticsManager tradeStatisticsManager) {
|
||||||
User user) {
|
this.coreOffersService = coreOffersService;
|
||||||
this.offerBookService = offerBookService;
|
this.paymentAccountsService = paymentAccountsService;
|
||||||
|
this.walletsService = walletsService;
|
||||||
this.tradeStatisticsManager = tradeStatisticsManager;
|
this.tradeStatisticsManager = tradeStatisticsManager;
|
||||||
this.createOfferService = createOfferService;
|
|
||||||
this.openOfferManager = openOfferManager;
|
|
||||||
this.user = user;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getVersion() {
|
public String getVersion() {
|
||||||
return Version.VERSION;
|
return Version.VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TradeStatistics2> getTradeStatistics() {
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
return new ArrayList<>(tradeStatisticsManager.getObservableTradeStatisticsSet());
|
// Offers
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public List<Offer> getOffers(String direction, String fiatCurrencyCode) {
|
||||||
|
return coreOffersService.getOffers(direction, fiatCurrencyCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Offer> getOffers() {
|
public void createOffer(String currencyCode,
|
||||||
return offerBookService.getOffers();
|
String directionAsString,
|
||||||
|
long priceAsLong,
|
||||||
|
boolean useMarketBasedPrice,
|
||||||
|
double marketPriceMargin,
|
||||||
|
long amountAsLong,
|
||||||
|
long minAmountAsLong,
|
||||||
|
double buyerSecurityDeposit,
|
||||||
|
String paymentAccountId,
|
||||||
|
TransactionResultHandler resultHandler) {
|
||||||
|
coreOffersService.createOffer(currencyCode,
|
||||||
|
directionAsString,
|
||||||
|
priceAsLong,
|
||||||
|
useMarketBasedPrice,
|
||||||
|
marketPriceMargin,
|
||||||
|
amountAsLong,
|
||||||
|
minAmountAsLong,
|
||||||
|
buyerSecurityDeposit,
|
||||||
|
paymentAccountId,
|
||||||
|
resultHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<PaymentAccount> getPaymentAccounts() {
|
public void createOffer(String offerId,
|
||||||
return user.getPaymentAccounts();
|
String currencyCode,
|
||||||
}
|
OfferPayload.Direction direction,
|
||||||
|
Price price,
|
||||||
public void placeOffer(String currencyCode,
|
boolean useMarketBasedPrice,
|
||||||
String directionAsString,
|
double marketPriceMargin,
|
||||||
long priceAsLong,
|
Coin amount,
|
||||||
boolean useMarketBasedPrice,
|
Coin minAmount,
|
||||||
double marketPriceMargin,
|
double buyerSecurityDeposit,
|
||||||
long amountAsLong,
|
PaymentAccount paymentAccount,
|
||||||
long minAmountAsLong,
|
boolean useSavingsWallet,
|
||||||
double buyerSecurityDeposit,
|
TransactionResultHandler resultHandler) {
|
||||||
String paymentAccountId,
|
coreOffersService.createOffer(offerId,
|
||||||
TransactionResultHandler resultHandler) {
|
|
||||||
String offerId = createOfferService.getRandomOfferId();
|
|
||||||
OfferPayload.Direction direction = OfferPayload.Direction.valueOf(directionAsString);
|
|
||||||
Price price = Price.valueOf(currencyCode, priceAsLong);
|
|
||||||
Coin amount = Coin.valueOf(amountAsLong);
|
|
||||||
Coin minAmount = Coin.valueOf(minAmountAsLong);
|
|
||||||
PaymentAccount paymentAccount = user.getPaymentAccount(paymentAccountId);
|
|
||||||
// We don't support atm funding from external wallet to keep it simple
|
|
||||||
boolean useSavingsWallet = true;
|
|
||||||
|
|
||||||
placeOffer(offerId,
|
|
||||||
currencyCode,
|
currencyCode,
|
||||||
direction,
|
direction,
|
||||||
price,
|
price,
|
||||||
@ -115,34 +121,59 @@ public class CoreApi {
|
|||||||
resultHandler);
|
resultHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void placeOffer(String offerId,
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
String currencyCode,
|
// PaymentAccounts
|
||||||
OfferPayload.Direction direction,
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
Price price,
|
|
||||||
boolean useMarketBasedPrice,
|
|
||||||
double marketPriceMargin,
|
|
||||||
Coin amount,
|
|
||||||
Coin minAmount,
|
|
||||||
double buyerSecurityDeposit,
|
|
||||||
PaymentAccount paymentAccount,
|
|
||||||
boolean useSavingsWallet,
|
|
||||||
TransactionResultHandler resultHandler) {
|
|
||||||
Offer offer = createOfferService.createAndGetOffer(offerId,
|
|
||||||
direction,
|
|
||||||
currencyCode,
|
|
||||||
amount,
|
|
||||||
minAmount,
|
|
||||||
price,
|
|
||||||
useMarketBasedPrice,
|
|
||||||
marketPriceMargin,
|
|
||||||
buyerSecurityDeposit,
|
|
||||||
paymentAccount);
|
|
||||||
|
|
||||||
openOfferManager.placeOffer(offer,
|
public void createPaymentAccount(String accountName, String accountNumber, String fiatCurrencyCode) {
|
||||||
buyerSecurityDeposit,
|
paymentAccountsService.createPaymentAccount(accountName, accountNumber, fiatCurrencyCode);
|
||||||
useSavingsWallet,
|
|
||||||
resultHandler,
|
|
||||||
log::error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<PaymentAccount> getPaymentAccounts() {
|
||||||
|
return paymentAccountsService.getPaymentAccounts();
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Wallets
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public long getAvailableBalance() {
|
||||||
|
return walletsService.getAvailableBalance();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getAddressBalance(String addressString) {
|
||||||
|
return walletsService.getAddressBalance(addressString);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddressBalanceInfo getAddressBalanceInfo(String addressString) {
|
||||||
|
return walletsService.getAddressBalanceInfo(addressString);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AddressBalanceInfo> getFundingAddresses() {
|
||||||
|
return walletsService.getFundingAddresses();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWalletPassword(String password, String newPassword) {
|
||||||
|
walletsService.setWalletPassword(password, newPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void lockWallet() {
|
||||||
|
walletsService.lockWallet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unlockWallet(String password, long timeout) {
|
||||||
|
walletsService.unlockWallet(password, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeWalletPassword(String password) {
|
||||||
|
walletsService.removeWalletPassword(password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TradeStatistics2> getTradeStatistics() {
|
||||||
|
return new ArrayList<>(tradeStatisticsManager.getObservableTradeStatisticsSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumConfirmationsForMostRecentTransaction(String addressString) {
|
||||||
|
return walletsService.getNumConfirmationsForMostRecentTransaction(addressString);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
145
core/src/main/java/bisq/core/grpc/CoreOffersService.java
Normal file
145
core/src/main/java/bisq/core/grpc/CoreOffersService.java
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* 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.grpc;
|
||||||
|
|
||||||
|
import bisq.core.monetary.Price;
|
||||||
|
import bisq.core.offer.CreateOfferService;
|
||||||
|
import bisq.core.offer.Offer;
|
||||||
|
import bisq.core.offer.OfferBookService;
|
||||||
|
import bisq.core.offer.OfferPayload;
|
||||||
|
import bisq.core.offer.OpenOfferManager;
|
||||||
|
import bisq.core.payment.PaymentAccount;
|
||||||
|
import bisq.core.trade.handlers.TransactionResultHandler;
|
||||||
|
import bisq.core.user.User;
|
||||||
|
|
||||||
|
import org.bitcoinj.core.Coin;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import static bisq.core.offer.OfferPayload.Direction.BUY;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class CoreOffersService {
|
||||||
|
|
||||||
|
private final CreateOfferService createOfferService;
|
||||||
|
private final OfferBookService offerBookService;
|
||||||
|
private final OpenOfferManager openOfferManager;
|
||||||
|
private final User user;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public CoreOffersService(CreateOfferService createOfferService,
|
||||||
|
OfferBookService offerBookService,
|
||||||
|
OpenOfferManager openOfferManager,
|
||||||
|
User user) {
|
||||||
|
this.createOfferService = createOfferService;
|
||||||
|
this.offerBookService = offerBookService;
|
||||||
|
this.openOfferManager = openOfferManager;
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Offer> getOffers(String direction, String fiatCurrencyCode) {
|
||||||
|
List<Offer> offers = offerBookService.getOffers().stream()
|
||||||
|
.filter(o -> {
|
||||||
|
var offerOfWantedDirection = o.getDirection().name().equalsIgnoreCase(direction);
|
||||||
|
var offerInWantedCurrency = o.getOfferPayload().getCounterCurrencyCode().equalsIgnoreCase(fiatCurrencyCode);
|
||||||
|
return offerOfWantedDirection && offerInWantedCurrency;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// A buyer probably wants to see sell orders in price ascending order.
|
||||||
|
// A seller probably wants to see buy orders in price descending order.
|
||||||
|
if (direction.equalsIgnoreCase(BUY.name()))
|
||||||
|
offers.sort(Comparator.comparing(Offer::getPrice).reversed());
|
||||||
|
else
|
||||||
|
offers.sort(Comparator.comparing(Offer::getPrice));
|
||||||
|
|
||||||
|
return offers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createOffer(String currencyCode,
|
||||||
|
String directionAsString,
|
||||||
|
long priceAsLong,
|
||||||
|
boolean useMarketBasedPrice,
|
||||||
|
double marketPriceMargin,
|
||||||
|
long amountAsLong,
|
||||||
|
long minAmountAsLong,
|
||||||
|
double buyerSecurityDeposit,
|
||||||
|
String paymentAccountId,
|
||||||
|
TransactionResultHandler resultHandler) {
|
||||||
|
String offerId = createOfferService.getRandomOfferId();
|
||||||
|
OfferPayload.Direction direction = OfferPayload.Direction.valueOf(directionAsString);
|
||||||
|
Price price = Price.valueOf(currencyCode, priceAsLong);
|
||||||
|
Coin amount = Coin.valueOf(amountAsLong);
|
||||||
|
Coin minAmount = Coin.valueOf(minAmountAsLong);
|
||||||
|
PaymentAccount paymentAccount = user.getPaymentAccount(paymentAccountId);
|
||||||
|
// We don't support atm funding from external wallet to keep it simple
|
||||||
|
boolean useSavingsWallet = true;
|
||||||
|
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
createOffer(offerId,
|
||||||
|
currencyCode,
|
||||||
|
direction,
|
||||||
|
price,
|
||||||
|
useMarketBasedPrice,
|
||||||
|
marketPriceMargin,
|
||||||
|
amount,
|
||||||
|
minAmount,
|
||||||
|
buyerSecurityDeposit,
|
||||||
|
paymentAccount,
|
||||||
|
useSavingsWallet,
|
||||||
|
resultHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createOffer(String offerId,
|
||||||
|
String currencyCode,
|
||||||
|
OfferPayload.Direction direction,
|
||||||
|
Price price,
|
||||||
|
boolean useMarketBasedPrice,
|
||||||
|
double marketPriceMargin,
|
||||||
|
Coin amount,
|
||||||
|
Coin minAmount,
|
||||||
|
double buyerSecurityDeposit,
|
||||||
|
PaymentAccount paymentAccount,
|
||||||
|
boolean useSavingsWallet,
|
||||||
|
TransactionResultHandler resultHandler) {
|
||||||
|
Coin useDefaultTxFee = Coin.ZERO;
|
||||||
|
Offer offer = createOfferService.createAndGetOffer(offerId,
|
||||||
|
direction,
|
||||||
|
currencyCode,
|
||||||
|
amount,
|
||||||
|
minAmount,
|
||||||
|
price,
|
||||||
|
useDefaultTxFee,
|
||||||
|
useMarketBasedPrice,
|
||||||
|
marketPriceMargin,
|
||||||
|
buyerSecurityDeposit,
|
||||||
|
paymentAccount);
|
||||||
|
|
||||||
|
openOfferManager.placeOffer(offer,
|
||||||
|
buyerSecurityDeposit,
|
||||||
|
useSavingsWallet,
|
||||||
|
resultHandler,
|
||||||
|
log::error);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* 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.grpc;
|
||||||
|
|
||||||
|
import bisq.core.account.witness.AccountAgeWitnessService;
|
||||||
|
import bisq.core.locale.FiatCurrency;
|
||||||
|
import bisq.core.payment.PaymentAccount;
|
||||||
|
import bisq.core.payment.PaymentAccountFactory;
|
||||||
|
import bisq.core.payment.PerfectMoneyAccount;
|
||||||
|
import bisq.core.payment.payload.PaymentMethod;
|
||||||
|
import bisq.core.user.User;
|
||||||
|
|
||||||
|
import bisq.common.config.Config;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class CorePaymentAccountsService {
|
||||||
|
|
||||||
|
private final Config config;
|
||||||
|
private final AccountAgeWitnessService accountAgeWitnessService;
|
||||||
|
private final User user;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public CorePaymentAccountsService(Config config,
|
||||||
|
AccountAgeWitnessService accountAgeWitnessService,
|
||||||
|
User user) {
|
||||||
|
this.config = config;
|
||||||
|
this.accountAgeWitnessService = accountAgeWitnessService;
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createPaymentAccount(String accountName, String accountNumber, String fiatCurrencyCode) {
|
||||||
|
// Create and persist a PerfectMoney dummy payment account. There is no guard
|
||||||
|
// against creating accounts with duplicate names & numbers, only the uuid and
|
||||||
|
// creation date are unique.
|
||||||
|
PaymentMethod dummyPaymentMethod = PaymentMethod.getDummyPaymentMethod(PaymentMethod.PERFECT_MONEY_ID);
|
||||||
|
PaymentAccount paymentAccount = PaymentAccountFactory.getPaymentAccount(dummyPaymentMethod);
|
||||||
|
paymentAccount.init();
|
||||||
|
paymentAccount.setAccountName(accountName);
|
||||||
|
((PerfectMoneyAccount) paymentAccount).setAccountNr(accountNumber);
|
||||||
|
paymentAccount.setSingleTradeCurrency(new FiatCurrency(fiatCurrencyCode.toUpperCase()));
|
||||||
|
user.addPaymentAccount(paymentAccount);
|
||||||
|
|
||||||
|
// Don't do this on mainnet until thoroughly tested.
|
||||||
|
if (config.baseCurrencyNetwork.isRegtest())
|
||||||
|
accountAgeWitnessService.publishMyAccountAgeWitness(paymentAccount.getPaymentAccountPayload());
|
||||||
|
|
||||||
|
log.info("Payment account {} saved", paymentAccount.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<PaymentAccount> getPaymentAccounts() {
|
||||||
|
return user.getPaymentAccounts();
|
||||||
|
}
|
||||||
|
}
|
@ -1,28 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* 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.grpc;
|
package bisq.core.grpc;
|
||||||
|
|
||||||
import bisq.core.btc.Balances;
|
import bisq.core.btc.Balances;
|
||||||
|
import bisq.core.btc.model.AddressEntry;
|
||||||
|
import bisq.core.btc.wallet.BtcWalletService;
|
||||||
import bisq.core.btc.wallet.WalletsManager;
|
import bisq.core.btc.wallet.WalletsManager;
|
||||||
|
import bisq.core.grpc.model.AddressBalanceInfo;
|
||||||
|
|
||||||
|
import org.bitcoinj.core.Address;
|
||||||
|
import org.bitcoinj.core.TransactionConfidence;
|
||||||
import org.bitcoinj.crypto.KeyCrypterScrypt;
|
import org.bitcoinj.crypto.KeyCrypterScrypt;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
import com.google.common.cache.CacheLoader;
|
||||||
|
import com.google.common.cache.LoadingCache;
|
||||||
|
|
||||||
import org.spongycastle.crypto.params.KeyParameter;
|
import org.spongycastle.crypto.params.KeyParameter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static java.lang.String.format;
|
||||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
class CoreWalletService {
|
class CoreWalletsService {
|
||||||
|
|
||||||
private final Balances balances;
|
private final Balances balances;
|
||||||
private final WalletsManager walletsManager;
|
private final WalletsManager walletsManager;
|
||||||
|
private final BtcWalletService btcWalletService;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private TimerTask lockTask;
|
private TimerTask lockTask;
|
||||||
@ -31,17 +63,17 @@ class CoreWalletService {
|
|||||||
private KeyParameter tempAesKey;
|
private KeyParameter tempAesKey;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public CoreWalletService(Balances balances, WalletsManager walletsManager) {
|
public CoreWalletsService(Balances balances,
|
||||||
|
WalletsManager walletsManager,
|
||||||
|
BtcWalletService btcWalletService) {
|
||||||
this.balances = balances;
|
this.balances = balances;
|
||||||
this.walletsManager = walletsManager;
|
this.walletsManager = walletsManager;
|
||||||
|
this.btcWalletService = btcWalletService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getAvailableBalance() {
|
public long getAvailableBalance() {
|
||||||
if (!walletsManager.areWalletsAvailable())
|
verifyWalletsAreAvailable();
|
||||||
throw new IllegalStateException("wallet is not yet available");
|
verifyEncryptedWalletIsUnlocked();
|
||||||
|
|
||||||
if (walletsManager.areWalletsEncrypted() && tempAesKey == null)
|
|
||||||
throw new IllegalStateException("wallet is locked");
|
|
||||||
|
|
||||||
var balance = balances.getAvailableBalance().get();
|
var balance = balances.getAvailableBalance().get();
|
||||||
if (balance == null)
|
if (balance == null)
|
||||||
@ -50,9 +82,61 @@ class CoreWalletService {
|
|||||||
return balance.getValue();
|
return balance.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getAddressBalance(String addressString) {
|
||||||
|
Address address = getAddressEntry(addressString).getAddress();
|
||||||
|
return btcWalletService.getBalanceForAddress(address).value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddressBalanceInfo getAddressBalanceInfo(String addressString) {
|
||||||
|
var satoshiBalance = getAddressBalance(addressString);
|
||||||
|
var numConfirmations = getNumConfirmationsForMostRecentTransaction(addressString);
|
||||||
|
return new AddressBalanceInfo(addressString, satoshiBalance, numConfirmations);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AddressBalanceInfo> getFundingAddresses() {
|
||||||
|
verifyWalletsAreAvailable();
|
||||||
|
verifyEncryptedWalletIsUnlocked();
|
||||||
|
|
||||||
|
// Create a new funding address if none exists.
|
||||||
|
if (btcWalletService.getAvailableAddressEntries().size() == 0)
|
||||||
|
btcWalletService.getFreshAddressEntry();
|
||||||
|
|
||||||
|
List<String> addressStrings =
|
||||||
|
btcWalletService
|
||||||
|
.getAvailableAddressEntries()
|
||||||
|
.stream()
|
||||||
|
.map(AddressEntry::getAddressString)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// getAddressBalance is memoized, because we'll map it over addresses twice.
|
||||||
|
// To get the balances, we'll be using .getUnchecked, because we know that
|
||||||
|
// this::getAddressBalance cannot return null.
|
||||||
|
var balances = memoize(this::getAddressBalance);
|
||||||
|
|
||||||
|
boolean noAddressHasZeroBalance =
|
||||||
|
addressStrings.stream()
|
||||||
|
.allMatch(addressString -> balances.getUnchecked(addressString) != 0);
|
||||||
|
|
||||||
|
if (noAddressHasZeroBalance) {
|
||||||
|
var newZeroBalanceAddress = btcWalletService.getFreshAddressEntry();
|
||||||
|
addressStrings.add(newZeroBalanceAddress.getAddressString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return addressStrings.stream().map(address ->
|
||||||
|
new AddressBalanceInfo(address,
|
||||||
|
balances.getUnchecked(address),
|
||||||
|
getNumConfirmationsForMostRecentTransaction(address)))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumConfirmationsForMostRecentTransaction(String addressString) {
|
||||||
|
Address address = getAddressEntry(addressString).getAddress();
|
||||||
|
TransactionConfidence confidence = btcWalletService.getConfidenceForAddress(address);
|
||||||
|
return confidence == null ? 0 : confidence.getDepthInBlocks();
|
||||||
|
}
|
||||||
|
|
||||||
public void setWalletPassword(String password, String newPassword) {
|
public void setWalletPassword(String password, String newPassword) {
|
||||||
if (!walletsManager.areWalletsAvailable())
|
verifyWalletsAreAvailable();
|
||||||
throw new IllegalStateException("wallet is not yet available");
|
|
||||||
|
|
||||||
KeyCrypterScrypt keyCrypterScrypt = getKeyCrypterScrypt();
|
KeyCrypterScrypt keyCrypterScrypt = getKeyCrypterScrypt();
|
||||||
|
|
||||||
@ -141,6 +225,12 @@ class CoreWalletService {
|
|||||||
walletsManager.backupWallets();
|
walletsManager.backupWallets();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Throws a RuntimeException if wallets are not available (encrypted or not).
|
||||||
|
private void verifyWalletsAreAvailable() {
|
||||||
|
if (!walletsManager.areWalletsAvailable())
|
||||||
|
throw new IllegalStateException("wallet is not yet available");
|
||||||
|
}
|
||||||
|
|
||||||
// Throws a RuntimeException if wallets are not available or not encrypted.
|
// Throws a RuntimeException if wallets are not available or not encrypted.
|
||||||
private void verifyWalletIsAvailableAndEncrypted() {
|
private void verifyWalletIsAvailableAndEncrypted() {
|
||||||
if (!walletsManager.areWalletsAvailable())
|
if (!walletsManager.areWalletsAvailable())
|
||||||
@ -150,10 +240,42 @@ class CoreWalletService {
|
|||||||
throw new IllegalStateException("wallet is not encrypted with a password");
|
throw new IllegalStateException("wallet is not encrypted with a password");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Throws a RuntimeException if wallets are encrypted and locked.
|
||||||
|
private void verifyEncryptedWalletIsUnlocked() {
|
||||||
|
if (walletsManager.areWalletsEncrypted() && tempAesKey == null)
|
||||||
|
throw new IllegalStateException("wallet is locked");
|
||||||
|
}
|
||||||
|
|
||||||
private KeyCrypterScrypt getKeyCrypterScrypt() {
|
private KeyCrypterScrypt getKeyCrypterScrypt() {
|
||||||
KeyCrypterScrypt keyCrypterScrypt = walletsManager.getKeyCrypterScrypt();
|
KeyCrypterScrypt keyCrypterScrypt = walletsManager.getKeyCrypterScrypt();
|
||||||
if (keyCrypterScrypt == null)
|
if (keyCrypterScrypt == null)
|
||||||
throw new IllegalStateException("wallet encrypter is not available");
|
throw new IllegalStateException("wallet encrypter is not available");
|
||||||
return keyCrypterScrypt;
|
return keyCrypterScrypt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AddressEntry getAddressEntry(String addressString) {
|
||||||
|
Optional<AddressEntry> addressEntry =
|
||||||
|
btcWalletService.getAddressEntryListAsImmutableList().stream()
|
||||||
|
.filter(e -> addressString.equals(e.getAddressString()))
|
||||||
|
.findFirst();
|
||||||
|
|
||||||
|
if (!addressEntry.isPresent())
|
||||||
|
throw new IllegalStateException(format("address %s not found in wallet", addressString));
|
||||||
|
|
||||||
|
return addressEntry.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Memoization stores the results of expensive function calls and returns
|
||||||
|
* the cached result when the same input occurs again.
|
||||||
|
*
|
||||||
|
* Resulting LoadingCache is used by calling `.get(input I)` or
|
||||||
|
* `.getUnchecked(input I)`, depending on whether or not `f` can return null.
|
||||||
|
* That's because CacheLoader throws an exception on null output from `f`.
|
||||||
|
*/
|
||||||
|
private static <I, O> LoadingCache<I, O> memoize(Function<I, O> f) {
|
||||||
|
// f::apply is used, because Guava 20.0 Function doesn't yet extend
|
||||||
|
// Java Function.
|
||||||
|
return CacheBuilder.newBuilder().build(CacheLoader.from(f::apply));
|
||||||
|
}
|
||||||
}
|
}
|
105
core/src/main/java/bisq/core/grpc/GrpcOffersService.java
Normal file
105
core/src/main/java/bisq/core/grpc/GrpcOffersService.java
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* 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.grpc;
|
||||||
|
|
||||||
|
import bisq.core.grpc.model.OfferInfo;
|
||||||
|
import bisq.core.trade.handlers.TransactionResultHandler;
|
||||||
|
|
||||||
|
import bisq.proto.grpc.CreateOfferReply;
|
||||||
|
import bisq.proto.grpc.CreateOfferRequest;
|
||||||
|
import bisq.proto.grpc.GetOffersReply;
|
||||||
|
import bisq.proto.grpc.GetOffersRequest;
|
||||||
|
import bisq.proto.grpc.OffersGrpc;
|
||||||
|
|
||||||
|
import io.grpc.stub.StreamObserver;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
class GrpcOffersService extends OffersGrpc.OffersImplBase {
|
||||||
|
|
||||||
|
private final CoreApi coreApi;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public GrpcOffersService(CoreApi coreApi) {
|
||||||
|
this.coreApi = coreApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getOffers(GetOffersRequest req,
|
||||||
|
StreamObserver<GetOffersReply> responseObserver) {
|
||||||
|
// The client cannot see bisq.core.Offer or its fromProto method.
|
||||||
|
// We use the lighter weight OfferInfo proto wrapper instead, containing just
|
||||||
|
// enough fields to view and create offers.
|
||||||
|
List<OfferInfo> result = coreApi.getOffers(req.getDirection(), req.getFiatCurrencyCode())
|
||||||
|
.stream().map(offer -> new OfferInfo.OfferInfoBuilder()
|
||||||
|
.withId(offer.getId())
|
||||||
|
.withDirection(offer.getDirection().name())
|
||||||
|
.withPrice(offer.getPrice().getValue())
|
||||||
|
.withUseMarketBasedPrice(offer.isUseMarketBasedPrice())
|
||||||
|
.withMarketPriceMargin(offer.getMarketPriceMargin())
|
||||||
|
.withAmount(offer.getAmount().value)
|
||||||
|
.withMinAmount(offer.getMinAmount().value)
|
||||||
|
.withVolume(offer.getVolume().getValue())
|
||||||
|
.withMinVolume(offer.getMinVolume().getValue())
|
||||||
|
.withBuyerSecurityDeposit(offer.getBuyerSecurityDeposit().value)
|
||||||
|
.withPaymentAccountId("") // only used when creating offer (?)
|
||||||
|
.withPaymentMethodId(offer.getPaymentMethod().getId())
|
||||||
|
.withPaymentMethodShortName(offer.getPaymentMethod().getShortName())
|
||||||
|
.withBaseCurrencyCode(offer.getOfferPayload().getBaseCurrencyCode())
|
||||||
|
.withCounterCurrencyCode(offer.getOfferPayload().getCounterCurrencyCode())
|
||||||
|
.withDate(offer.getDate().getTime())
|
||||||
|
.build())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
var reply = GetOffersReply.newBuilder()
|
||||||
|
.addAllOffers(
|
||||||
|
result.stream()
|
||||||
|
.map(OfferInfo::toProtoMessage)
|
||||||
|
.collect(Collectors.toList()))
|
||||||
|
.build();
|
||||||
|
responseObserver.onNext(reply);
|
||||||
|
responseObserver.onCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createOffer(CreateOfferRequest req,
|
||||||
|
StreamObserver<CreateOfferReply> responseObserver) {
|
||||||
|
TransactionResultHandler resultHandler = transaction -> {
|
||||||
|
CreateOfferReply reply = CreateOfferReply.newBuilder().setResult(true).build();
|
||||||
|
responseObserver.onNext(reply);
|
||||||
|
responseObserver.onCompleted();
|
||||||
|
};
|
||||||
|
coreApi.createOffer(
|
||||||
|
req.getCurrencyCode(),
|
||||||
|
req.getDirection(),
|
||||||
|
req.getPrice(),
|
||||||
|
req.getUseMarketBasedPrice(),
|
||||||
|
req.getMarketPriceMargin(),
|
||||||
|
req.getAmount(),
|
||||||
|
req.getMinAmount(),
|
||||||
|
req.getBuyerSecurityDeposit(),
|
||||||
|
req.getPaymentAccountId(),
|
||||||
|
resultHandler);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* 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.grpc;
|
||||||
|
|
||||||
|
import bisq.core.payment.PaymentAccount;
|
||||||
|
|
||||||
|
import bisq.proto.grpc.CreatePaymentAccountReply;
|
||||||
|
import bisq.proto.grpc.CreatePaymentAccountRequest;
|
||||||
|
import bisq.proto.grpc.GetPaymentAccountsReply;
|
||||||
|
import bisq.proto.grpc.GetPaymentAccountsRequest;
|
||||||
|
import bisq.proto.grpc.PaymentAccountsGrpc;
|
||||||
|
|
||||||
|
import io.grpc.stub.StreamObserver;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
|
public class GrpcPaymentAccountsService extends PaymentAccountsGrpc.PaymentAccountsImplBase {
|
||||||
|
|
||||||
|
private final CoreApi coreApi;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public GrpcPaymentAccountsService(CoreApi coreApi) {
|
||||||
|
this.coreApi = coreApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createPaymentAccount(CreatePaymentAccountRequest req,
|
||||||
|
StreamObserver<CreatePaymentAccountReply> responseObserver) {
|
||||||
|
coreApi.createPaymentAccount(req.getAccountName(), req.getAccountNumber(), req.getFiatCurrencyCode());
|
||||||
|
var reply = CreatePaymentAccountReply.newBuilder().build();
|
||||||
|
responseObserver.onNext(reply);
|
||||||
|
responseObserver.onCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getPaymentAccounts(GetPaymentAccountsRequest req,
|
||||||
|
StreamObserver<GetPaymentAccountsReply> responseObserver) {
|
||||||
|
var tradeStatistics = coreApi.getPaymentAccounts().stream()
|
||||||
|
.map(PaymentAccount::toProtoMessage)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
var reply = GetPaymentAccountsReply.newBuilder().addAllPaymentAccounts(tradeStatistics).build();
|
||||||
|
responseObserver.onNext(reply);
|
||||||
|
responseObserver.onCompleted();
|
||||||
|
}
|
||||||
|
}
|
@ -17,28 +17,16 @@
|
|||||||
|
|
||||||
package bisq.core.grpc;
|
package bisq.core.grpc;
|
||||||
|
|
||||||
import bisq.core.offer.Offer;
|
|
||||||
import bisq.core.payment.PaymentAccount;
|
|
||||||
import bisq.core.trade.handlers.TransactionResultHandler;
|
|
||||||
import bisq.core.trade.statistics.TradeStatistics2;
|
import bisq.core.trade.statistics.TradeStatistics2;
|
||||||
|
|
||||||
import bisq.common.config.Config;
|
import bisq.common.config.Config;
|
||||||
|
|
||||||
import bisq.proto.grpc.GetOffersGrpc;
|
|
||||||
import bisq.proto.grpc.GetOffersReply;
|
|
||||||
import bisq.proto.grpc.GetOffersRequest;
|
|
||||||
import bisq.proto.grpc.GetPaymentAccountsGrpc;
|
|
||||||
import bisq.proto.grpc.GetPaymentAccountsReply;
|
|
||||||
import bisq.proto.grpc.GetPaymentAccountsRequest;
|
|
||||||
import bisq.proto.grpc.GetTradeStatisticsGrpc;
|
import bisq.proto.grpc.GetTradeStatisticsGrpc;
|
||||||
import bisq.proto.grpc.GetTradeStatisticsReply;
|
import bisq.proto.grpc.GetTradeStatisticsReply;
|
||||||
import bisq.proto.grpc.GetTradeStatisticsRequest;
|
import bisq.proto.grpc.GetTradeStatisticsRequest;
|
||||||
import bisq.proto.grpc.GetVersionGrpc;
|
import bisq.proto.grpc.GetVersionGrpc;
|
||||||
import bisq.proto.grpc.GetVersionReply;
|
import bisq.proto.grpc.GetVersionReply;
|
||||||
import bisq.proto.grpc.GetVersionRequest;
|
import bisq.proto.grpc.GetVersionRequest;
|
||||||
import bisq.proto.grpc.PlaceOfferGrpc;
|
|
||||||
import bisq.proto.grpc.PlaceOfferReply;
|
|
||||||
import bisq.proto.grpc.PlaceOfferRequest;
|
|
||||||
|
|
||||||
import io.grpc.Server;
|
import io.grpc.Server;
|
||||||
import io.grpc.ServerBuilder;
|
import io.grpc.ServerBuilder;
|
||||||
@ -60,15 +48,18 @@ public class GrpcServer {
|
|||||||
private final Server server;
|
private final Server server;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public GrpcServer(Config config, CoreApi coreApi, GrpcWalletService walletService) {
|
public GrpcServer(Config config,
|
||||||
|
CoreApi coreApi,
|
||||||
|
GrpcOffersService offersService,
|
||||||
|
GrpcPaymentAccountsService paymentAccountsService,
|
||||||
|
GrpcWalletsService walletsService) {
|
||||||
this.coreApi = coreApi;
|
this.coreApi = coreApi;
|
||||||
this.server = ServerBuilder.forPort(config.apiPort)
|
this.server = ServerBuilder.forPort(config.apiPort)
|
||||||
.addService(new GetVersionService())
|
.addService(new GetVersionService())
|
||||||
.addService(new GetTradeStatisticsService())
|
.addService(new GetTradeStatisticsService())
|
||||||
.addService(new GetOffersService())
|
.addService(offersService)
|
||||||
.addService(new GetPaymentAccountsService())
|
.addService(paymentAccountsService)
|
||||||
.addService(new PlaceOfferService())
|
.addService(walletsService)
|
||||||
.addService(walletService)
|
|
||||||
.intercept(new PasswordAuthInterceptor(config.apiPassword))
|
.intercept(new PasswordAuthInterceptor(config.apiPassword))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
@ -95,7 +86,6 @@ public class GrpcServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class GetTradeStatisticsService extends GetTradeStatisticsGrpc.GetTradeStatisticsImplBase {
|
class GetTradeStatisticsService extends GetTradeStatisticsGrpc.GetTradeStatisticsImplBase {
|
||||||
@Override
|
@Override
|
||||||
public void getTradeStatistics(GetTradeStatisticsRequest req,
|
public void getTradeStatistics(GetTradeStatisticsRequest req,
|
||||||
@ -110,55 +100,4 @@ public class GrpcServer {
|
|||||||
responseObserver.onCompleted();
|
responseObserver.onCompleted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GetOffersService extends GetOffersGrpc.GetOffersImplBase {
|
|
||||||
@Override
|
|
||||||
public void getOffers(GetOffersRequest req, StreamObserver<GetOffersReply> responseObserver) {
|
|
||||||
|
|
||||||
var tradeStatistics = coreApi.getOffers().stream()
|
|
||||||
.map(Offer::toProtoMessage)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
var reply = GetOffersReply.newBuilder().addAllOffers(tradeStatistics).build();
|
|
||||||
responseObserver.onNext(reply);
|
|
||||||
responseObserver.onCompleted();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class GetPaymentAccountsService extends GetPaymentAccountsGrpc.GetPaymentAccountsImplBase {
|
|
||||||
@Override
|
|
||||||
public void getPaymentAccounts(GetPaymentAccountsRequest req,
|
|
||||||
StreamObserver<GetPaymentAccountsReply> responseObserver) {
|
|
||||||
|
|
||||||
var tradeStatistics = coreApi.getPaymentAccounts().stream()
|
|
||||||
.map(PaymentAccount::toProtoMessage)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
var reply = GetPaymentAccountsReply.newBuilder().addAllPaymentAccounts(tradeStatistics).build();
|
|
||||||
responseObserver.onNext(reply);
|
|
||||||
responseObserver.onCompleted();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class PlaceOfferService extends PlaceOfferGrpc.PlaceOfferImplBase {
|
|
||||||
@Override
|
|
||||||
public void placeOffer(PlaceOfferRequest req, StreamObserver<PlaceOfferReply> responseObserver) {
|
|
||||||
TransactionResultHandler resultHandler = transaction -> {
|
|
||||||
PlaceOfferReply reply = PlaceOfferReply.newBuilder().setResult(true).build();
|
|
||||||
responseObserver.onNext(reply);
|
|
||||||
responseObserver.onCompleted();
|
|
||||||
};
|
|
||||||
coreApi.placeOffer(
|
|
||||||
req.getCurrencyCode(),
|
|
||||||
req.getDirection(),
|
|
||||||
req.getPrice(),
|
|
||||||
req.getUseMarketBasedPrice(),
|
|
||||||
req.getMarketPriceMargin(),
|
|
||||||
req.getAmount(),
|
|
||||||
req.getMinAmount(),
|
|
||||||
req.getBuyerSecurityDeposit(),
|
|
||||||
req.getPaymentAccountId(),
|
|
||||||
resultHandler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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.grpc;
|
package bisq.core.grpc;
|
||||||
|
|
||||||
|
import bisq.core.grpc.model.AddressBalanceInfo;
|
||||||
|
|
||||||
|
import bisq.proto.grpc.GetAddressBalanceReply;
|
||||||
|
import bisq.proto.grpc.GetAddressBalanceRequest;
|
||||||
import bisq.proto.grpc.GetBalanceReply;
|
import bisq.proto.grpc.GetBalanceReply;
|
||||||
import bisq.proto.grpc.GetBalanceRequest;
|
import bisq.proto.grpc.GetBalanceRequest;
|
||||||
|
import bisq.proto.grpc.GetFundingAddressesReply;
|
||||||
|
import bisq.proto.grpc.GetFundingAddressesRequest;
|
||||||
import bisq.proto.grpc.LockWalletReply;
|
import bisq.proto.grpc.LockWalletReply;
|
||||||
import bisq.proto.grpc.LockWalletRequest;
|
import bisq.proto.grpc.LockWalletRequest;
|
||||||
import bisq.proto.grpc.RemoveWalletPasswordReply;
|
import bisq.proto.grpc.RemoveWalletPasswordReply;
|
||||||
@ -10,7 +33,7 @@ import bisq.proto.grpc.SetWalletPasswordReply;
|
|||||||
import bisq.proto.grpc.SetWalletPasswordRequest;
|
import bisq.proto.grpc.SetWalletPasswordRequest;
|
||||||
import bisq.proto.grpc.UnlockWalletReply;
|
import bisq.proto.grpc.UnlockWalletReply;
|
||||||
import bisq.proto.grpc.UnlockWalletRequest;
|
import bisq.proto.grpc.UnlockWalletRequest;
|
||||||
import bisq.proto.grpc.WalletGrpc;
|
import bisq.proto.grpc.WalletsGrpc;
|
||||||
|
|
||||||
import io.grpc.Status;
|
import io.grpc.Status;
|
||||||
import io.grpc.StatusRuntimeException;
|
import io.grpc.StatusRuntimeException;
|
||||||
@ -18,19 +41,22 @@ import io.grpc.stub.StreamObserver;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
class GrpcWalletService extends WalletGrpc.WalletImplBase {
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
private final CoreWalletService walletService;
|
class GrpcWalletsService extends WalletsGrpc.WalletsImplBase {
|
||||||
|
|
||||||
|
private final CoreApi coreApi;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public GrpcWalletService(CoreWalletService walletService) {
|
public GrpcWalletsService(CoreApi coreApi) {
|
||||||
this.walletService = walletService;
|
this.coreApi = coreApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getBalance(GetBalanceRequest req, StreamObserver<GetBalanceReply> responseObserver) {
|
public void getBalance(GetBalanceRequest req, StreamObserver<GetBalanceReply> responseObserver) {
|
||||||
try {
|
try {
|
||||||
long result = walletService.getAvailableBalance();
|
long result = coreApi.getAvailableBalance();
|
||||||
var reply = GetBalanceReply.newBuilder().setBalance(result).build();
|
var reply = GetBalanceReply.newBuilder().setBalance(result).build();
|
||||||
responseObserver.onNext(reply);
|
responseObserver.onNext(reply);
|
||||||
responseObserver.onCompleted();
|
responseObserver.onCompleted();
|
||||||
@ -41,11 +67,46 @@ class GrpcWalletService extends WalletGrpc.WalletImplBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getAddressBalance(GetAddressBalanceRequest req,
|
||||||
|
StreamObserver<GetAddressBalanceReply> responseObserver) {
|
||||||
|
try {
|
||||||
|
AddressBalanceInfo result = coreApi.getAddressBalanceInfo(req.getAddress());
|
||||||
|
var reply = GetAddressBalanceReply.newBuilder().setAddressBalanceInfo(result.toProtoMessage()).build();
|
||||||
|
responseObserver.onNext(reply);
|
||||||
|
responseObserver.onCompleted();
|
||||||
|
} catch (IllegalStateException cause) {
|
||||||
|
var ex = new StatusRuntimeException(Status.UNKNOWN.withDescription(cause.getMessage()));
|
||||||
|
responseObserver.onError(ex);
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getFundingAddresses(GetFundingAddressesRequest req,
|
||||||
|
StreamObserver<GetFundingAddressesReply> responseObserver) {
|
||||||
|
try {
|
||||||
|
List<AddressBalanceInfo> result = coreApi.getFundingAddresses();
|
||||||
|
var reply = GetFundingAddressesReply.newBuilder()
|
||||||
|
.addAllAddressBalanceInfo(
|
||||||
|
result.stream()
|
||||||
|
.map(AddressBalanceInfo::toProtoMessage)
|
||||||
|
.collect(Collectors.toList()))
|
||||||
|
.build();
|
||||||
|
responseObserver.onNext(reply);
|
||||||
|
responseObserver.onCompleted();
|
||||||
|
} catch (IllegalStateException cause) {
|
||||||
|
var ex = new StatusRuntimeException(Status.UNKNOWN.withDescription(cause.getMessage()));
|
||||||
|
responseObserver.onError(ex);
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setWalletPassword(SetWalletPasswordRequest req,
|
public void setWalletPassword(SetWalletPasswordRequest req,
|
||||||
StreamObserver<SetWalletPasswordReply> responseObserver) {
|
StreamObserver<SetWalletPasswordReply> responseObserver) {
|
||||||
try {
|
try {
|
||||||
walletService.setWalletPassword(req.getPassword(), req.getNewPassword());
|
coreApi.setWalletPassword(req.getPassword(), req.getNewPassword());
|
||||||
var reply = SetWalletPasswordReply.newBuilder().build();
|
var reply = SetWalletPasswordReply.newBuilder().build();
|
||||||
responseObserver.onNext(reply);
|
responseObserver.onNext(reply);
|
||||||
responseObserver.onCompleted();
|
responseObserver.onCompleted();
|
||||||
@ -60,7 +121,7 @@ class GrpcWalletService extends WalletGrpc.WalletImplBase {
|
|||||||
public void removeWalletPassword(RemoveWalletPasswordRequest req,
|
public void removeWalletPassword(RemoveWalletPasswordRequest req,
|
||||||
StreamObserver<RemoveWalletPasswordReply> responseObserver) {
|
StreamObserver<RemoveWalletPasswordReply> responseObserver) {
|
||||||
try {
|
try {
|
||||||
walletService.removeWalletPassword(req.getPassword());
|
coreApi.removeWalletPassword(req.getPassword());
|
||||||
var reply = RemoveWalletPasswordReply.newBuilder().build();
|
var reply = RemoveWalletPasswordReply.newBuilder().build();
|
||||||
responseObserver.onNext(reply);
|
responseObserver.onNext(reply);
|
||||||
responseObserver.onCompleted();
|
responseObserver.onCompleted();
|
||||||
@ -75,7 +136,7 @@ class GrpcWalletService extends WalletGrpc.WalletImplBase {
|
|||||||
public void lockWallet(LockWalletRequest req,
|
public void lockWallet(LockWalletRequest req,
|
||||||
StreamObserver<LockWalletReply> responseObserver) {
|
StreamObserver<LockWalletReply> responseObserver) {
|
||||||
try {
|
try {
|
||||||
walletService.lockWallet();
|
coreApi.lockWallet();
|
||||||
var reply = LockWalletReply.newBuilder().build();
|
var reply = LockWalletReply.newBuilder().build();
|
||||||
responseObserver.onNext(reply);
|
responseObserver.onNext(reply);
|
||||||
responseObserver.onCompleted();
|
responseObserver.onCompleted();
|
||||||
@ -90,7 +151,7 @@ class GrpcWalletService extends WalletGrpc.WalletImplBase {
|
|||||||
public void unlockWallet(UnlockWalletRequest req,
|
public void unlockWallet(UnlockWalletRequest req,
|
||||||
StreamObserver<UnlockWalletReply> responseObserver) {
|
StreamObserver<UnlockWalletReply> responseObserver) {
|
||||||
try {
|
try {
|
||||||
walletService.unlockWallet(req.getPassword(), req.getTimeout());
|
coreApi.unlockWallet(req.getPassword(), req.getTimeout());
|
||||||
var reply = UnlockWalletReply.newBuilder().build();
|
var reply = UnlockWalletReply.newBuilder().build();
|
||||||
responseObserver.onNext(reply);
|
responseObserver.onNext(reply);
|
||||||
responseObserver.onCompleted();
|
responseObserver.onCompleted();
|
@ -1,3 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* 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.grpc;
|
package bisq.core.grpc;
|
||||||
|
|
||||||
import io.grpc.Metadata;
|
import io.grpc.Metadata;
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* 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.grpc.model;
|
||||||
|
|
||||||
|
import bisq.common.Payload;
|
||||||
|
|
||||||
|
public class AddressBalanceInfo implements Payload {
|
||||||
|
|
||||||
|
private final String address;
|
||||||
|
private final long balance; // address' balance in satoshis
|
||||||
|
private final long numConfirmations; // # confirmations for address' most recent tx
|
||||||
|
|
||||||
|
public AddressBalanceInfo(String address, long balance, long numConfirmations) {
|
||||||
|
this.address = address;
|
||||||
|
this.balance = balance;
|
||||||
|
this.numConfirmations = numConfirmations;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// PROTO BUFFER
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public bisq.proto.grpc.AddressBalanceInfo toProtoMessage() {
|
||||||
|
return bisq.proto.grpc.AddressBalanceInfo.newBuilder()
|
||||||
|
.setAddress(address)
|
||||||
|
.setBalance(balance)
|
||||||
|
.setNumConfirmations(numConfirmations).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AddressBalanceInfo fromProto(bisq.proto.grpc.AddressBalanceInfo proto) {
|
||||||
|
return new AddressBalanceInfo(proto.getAddress(),
|
||||||
|
proto.getBalance(),
|
||||||
|
proto.getNumConfirmations());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "AddressBalanceInfo{" +
|
||||||
|
"address='" + address + '\'' +
|
||||||
|
", balance=" + balance +
|
||||||
|
", numConfirmations=" + numConfirmations +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
215
core/src/main/java/bisq/core/grpc/model/OfferInfo.java
Normal file
215
core/src/main/java/bisq/core/grpc/model/OfferInfo.java
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
/*
|
||||||
|
* 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.grpc.model;
|
||||||
|
|
||||||
|
import bisq.common.Payload;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@ToString
|
||||||
|
@Getter
|
||||||
|
public class OfferInfo implements Payload {
|
||||||
|
|
||||||
|
private final String id;
|
||||||
|
private final String direction;
|
||||||
|
private final long price;
|
||||||
|
private final boolean useMarketBasedPrice;
|
||||||
|
private final double marketPriceMargin;
|
||||||
|
private final long amount;
|
||||||
|
private final long minAmount;
|
||||||
|
private final long volume;
|
||||||
|
private final long minVolume;
|
||||||
|
private final long buyerSecurityDeposit;
|
||||||
|
private final String paymentAccountId; // only used when creating offer
|
||||||
|
private final String paymentMethodId;
|
||||||
|
private final String paymentMethodShortName;
|
||||||
|
// For fiat offer the baseCurrencyCode is BTC and the counterCurrencyCode is the fiat currency
|
||||||
|
// For altcoin offers it is the opposite. baseCurrencyCode is the altcoin and the counterCurrencyCode is BTC.
|
||||||
|
private final String baseCurrencyCode;
|
||||||
|
private final String counterCurrencyCode;
|
||||||
|
private final long date;
|
||||||
|
|
||||||
|
public OfferInfo(OfferInfoBuilder builder) {
|
||||||
|
this.id = builder.id;
|
||||||
|
this.direction = builder.direction;
|
||||||
|
this.price = builder.price;
|
||||||
|
this.useMarketBasedPrice = builder.useMarketBasedPrice;
|
||||||
|
this.marketPriceMargin = builder.marketPriceMargin;
|
||||||
|
this.amount = builder.amount;
|
||||||
|
this.minAmount = builder.minAmount;
|
||||||
|
this.volume = builder.volume;
|
||||||
|
this.minVolume = builder.minVolume;
|
||||||
|
this.buyerSecurityDeposit = builder.buyerSecurityDeposit;
|
||||||
|
this.paymentAccountId = builder.paymentAccountId;
|
||||||
|
this.paymentMethodId = builder.paymentMethodId;
|
||||||
|
this.paymentMethodShortName = builder.paymentMethodShortName;
|
||||||
|
this.baseCurrencyCode = builder.baseCurrencyCode;
|
||||||
|
this.counterCurrencyCode = builder.counterCurrencyCode;
|
||||||
|
this.date = builder.date;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// PROTO BUFFER
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public bisq.proto.grpc.OfferInfo toProtoMessage() {
|
||||||
|
return bisq.proto.grpc.OfferInfo.newBuilder()
|
||||||
|
.setId(id)
|
||||||
|
.setDirection(direction)
|
||||||
|
.setPrice(price)
|
||||||
|
.setUseMarketBasedPrice(useMarketBasedPrice)
|
||||||
|
.setMarketPriceMargin(marketPriceMargin)
|
||||||
|
.setAmount(amount)
|
||||||
|
.setMinAmount(minAmount)
|
||||||
|
.setVolume(volume)
|
||||||
|
.setMinVolume(minVolume)
|
||||||
|
.setBuyerSecurityDeposit(buyerSecurityDeposit)
|
||||||
|
.setPaymentAccountId(paymentAccountId)
|
||||||
|
.setPaymentMethodId(paymentMethodId)
|
||||||
|
.setPaymentMethodShortName(paymentMethodShortName)
|
||||||
|
.setBaseCurrencyCode(baseCurrencyCode)
|
||||||
|
.setCounterCurrencyCode(counterCurrencyCode)
|
||||||
|
.setDate(date)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OfferInfo fromProto(bisq.proto.grpc.OfferInfo proto) {
|
||||||
|
/*
|
||||||
|
TODO (will be needed by the createoffer method)
|
||||||
|
return new OfferInfo(proto.getOfferPayload().getId(),
|
||||||
|
proto.getOfferPayload().getDate());
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* OfferInfoBuilder helps avoid bungling use of a large OfferInfo constructor
|
||||||
|
* argument list. If consecutive argument values of the same type are not
|
||||||
|
* ordered correctly, the compiler won't complain but the resulting bugs could
|
||||||
|
* be hard to find and fix.
|
||||||
|
*/
|
||||||
|
public static class OfferInfoBuilder {
|
||||||
|
private String id;
|
||||||
|
private String direction;
|
||||||
|
private long price;
|
||||||
|
private boolean useMarketBasedPrice;
|
||||||
|
private double marketPriceMargin;
|
||||||
|
private long amount;
|
||||||
|
private long minAmount;
|
||||||
|
private long volume;
|
||||||
|
private long minVolume;
|
||||||
|
private long buyerSecurityDeposit;
|
||||||
|
private String paymentAccountId;
|
||||||
|
private String paymentMethodId;
|
||||||
|
private String paymentMethodShortName;
|
||||||
|
private String baseCurrencyCode;
|
||||||
|
private String counterCurrencyCode;
|
||||||
|
private long date;
|
||||||
|
|
||||||
|
public OfferInfoBuilder() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfferInfoBuilder withId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfferInfoBuilder withDirection(String direction) {
|
||||||
|
this.direction = direction;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfferInfoBuilder withPrice(long price) {
|
||||||
|
this.price = price;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfferInfoBuilder withUseMarketBasedPrice(boolean useMarketBasedPrice) {
|
||||||
|
this.useMarketBasedPrice = useMarketBasedPrice;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfferInfoBuilder withMarketPriceMargin(double useMarketBasedPrice) {
|
||||||
|
this.marketPriceMargin = useMarketBasedPrice;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfferInfoBuilder withAmount(long amount) {
|
||||||
|
this.amount = amount;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfferInfoBuilder withMinAmount(long minAmount) {
|
||||||
|
this.minAmount = minAmount;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfferInfoBuilder withVolume(long volume) {
|
||||||
|
this.volume = volume;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfferInfoBuilder withMinVolume(long minVolume) {
|
||||||
|
this.minVolume = minVolume;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfferInfoBuilder withBuyerSecurityDeposit(long buyerSecurityDeposit) {
|
||||||
|
this.buyerSecurityDeposit = buyerSecurityDeposit;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfferInfoBuilder withPaymentAccountId(String paymentAccountId) {
|
||||||
|
this.paymentAccountId = paymentAccountId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfferInfoBuilder withPaymentMethodId(String paymentMethodId) {
|
||||||
|
this.paymentMethodId = paymentMethodId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfferInfoBuilder withPaymentMethodShortName(String paymentMethodShortName) {
|
||||||
|
this.paymentMethodShortName = paymentMethodShortName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfferInfoBuilder withBaseCurrencyCode(String baseCurrencyCode) {
|
||||||
|
this.baseCurrencyCode = baseCurrencyCode;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfferInfoBuilder withCounterCurrencyCode(String counterCurrencyCode) {
|
||||||
|
this.counterCurrencyCode = counterCurrencyCode;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfferInfoBuilder withDate(long date) {
|
||||||
|
this.date = date;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OfferInfo build() {
|
||||||
|
return new OfferInfo(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -267,32 +267,39 @@ public class CurrencyUtil {
|
|||||||
return currencies;
|
return currencies;
|
||||||
}
|
}
|
||||||
|
|
||||||
//https://www.revolut.com/pa/faq#can-i-hold-multiple-currencies
|
// https://www.revolut.com/help/getting-started/exchanging-currencies/what-fiat-currencies-are-supported-for-holding-and-exchange
|
||||||
public static List<TradeCurrency> getAllRevolutCurrencies() {
|
public static List<TradeCurrency> getAllRevolutCurrencies() {
|
||||||
ArrayList<TradeCurrency> currencies = new ArrayList<>(Arrays.asList(
|
ArrayList<TradeCurrency> currencies = new ArrayList<>(Arrays.asList(
|
||||||
new FiatCurrency("USD"),
|
|
||||||
new FiatCurrency("GBP"),
|
|
||||||
new FiatCurrency("EUR"),
|
|
||||||
new FiatCurrency("PLN"),
|
|
||||||
new FiatCurrency("CHF"),
|
|
||||||
new FiatCurrency("DKK"),
|
|
||||||
new FiatCurrency("NOK"),
|
|
||||||
new FiatCurrency("SEK"),
|
|
||||||
new FiatCurrency("RON"),
|
|
||||||
new FiatCurrency("SGD"),
|
|
||||||
new FiatCurrency("HKD"),
|
|
||||||
new FiatCurrency("AUD"),
|
|
||||||
new FiatCurrency("NZD"),
|
|
||||||
new FiatCurrency("TRY"),
|
|
||||||
new FiatCurrency("ILS"),
|
|
||||||
new FiatCurrency("AED"),
|
new FiatCurrency("AED"),
|
||||||
|
new FiatCurrency("AUD"),
|
||||||
|
new FiatCurrency("BGN"),
|
||||||
new FiatCurrency("CAD"),
|
new FiatCurrency("CAD"),
|
||||||
|
new FiatCurrency("CHF"),
|
||||||
|
new FiatCurrency("CZK"),
|
||||||
|
new FiatCurrency("DKK"),
|
||||||
|
new FiatCurrency("EUR"),
|
||||||
|
new FiatCurrency("GBP"),
|
||||||
|
new FiatCurrency("HKD"),
|
||||||
|
new FiatCurrency("HRK"),
|
||||||
new FiatCurrency("HUF"),
|
new FiatCurrency("HUF"),
|
||||||
new FiatCurrency("INR"),
|
new FiatCurrency("ILS"),
|
||||||
|
new FiatCurrency("ISK"),
|
||||||
new FiatCurrency("JPY"),
|
new FiatCurrency("JPY"),
|
||||||
new FiatCurrency("MAD"),
|
new FiatCurrency("MAD"),
|
||||||
|
new FiatCurrency("MXN"),
|
||||||
|
new FiatCurrency("NOK"),
|
||||||
|
new FiatCurrency("NZD"),
|
||||||
|
new FiatCurrency("PLN"),
|
||||||
new FiatCurrency("QAR"),
|
new FiatCurrency("QAR"),
|
||||||
|
new FiatCurrency("RON"),
|
||||||
|
new FiatCurrency("RSD"),
|
||||||
|
new FiatCurrency("RUB"),
|
||||||
|
new FiatCurrency("SAR"),
|
||||||
|
new FiatCurrency("SEK"),
|
||||||
|
new FiatCurrency("SGD"),
|
||||||
new FiatCurrency("THB"),
|
new FiatCurrency("THB"),
|
||||||
|
new FiatCurrency("TRY"),
|
||||||
|
new FiatCurrency("USD"),
|
||||||
new FiatCurrency("ZAR")
|
new FiatCurrency("ZAR")
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -124,6 +124,7 @@ public class CreateOfferService {
|
|||||||
Coin amount,
|
Coin amount,
|
||||||
Coin minAmount,
|
Coin minAmount,
|
||||||
Price price,
|
Price price,
|
||||||
|
Coin txFee,
|
||||||
boolean useMarketBasedPrice,
|
boolean useMarketBasedPrice,
|
||||||
double marketPriceMargin,
|
double marketPriceMargin,
|
||||||
double buyerSecurityDepositAsDouble,
|
double buyerSecurityDepositAsDouble,
|
||||||
@ -183,6 +184,7 @@ public class CreateOfferService {
|
|||||||
List<String> acceptedBanks = PaymentAccountUtil.getAcceptedBanks(paymentAccount);
|
List<String> acceptedBanks = PaymentAccountUtil.getAcceptedBanks(paymentAccount);
|
||||||
double sellerSecurityDeposit = getSellerSecurityDepositAsDouble();
|
double sellerSecurityDeposit = getSellerSecurityDepositAsDouble();
|
||||||
Coin txFeeFromFeeService = getEstimatedFeeAndTxSize(amount, direction, buyerSecurityDepositAsDouble, sellerSecurityDeposit).first;
|
Coin txFeeFromFeeService = getEstimatedFeeAndTxSize(amount, direction, buyerSecurityDepositAsDouble, sellerSecurityDeposit).first;
|
||||||
|
Coin txFeeToUse = txFee.isPositive() ? txFee : txFeeFromFeeService;
|
||||||
Coin makerFeeAsCoin = getMakerFee(amount);
|
Coin makerFeeAsCoin = getMakerFee(amount);
|
||||||
boolean isCurrencyForMakerFeeBtc = OfferUtil.isCurrencyForMakerFeeBtc(preferences, bsqWalletService, amount);
|
boolean isCurrencyForMakerFeeBtc = OfferUtil.isCurrencyForMakerFeeBtc(preferences, bsqWalletService, amount);
|
||||||
Coin buyerSecurityDepositAsCoin = getBuyerSecurityDeposit(amount, buyerSecurityDepositAsDouble);
|
Coin buyerSecurityDepositAsCoin = getBuyerSecurityDeposit(amount, buyerSecurityDepositAsDouble);
|
||||||
@ -233,7 +235,7 @@ public class CreateOfferService {
|
|||||||
acceptedBanks,
|
acceptedBanks,
|
||||||
Version.VERSION,
|
Version.VERSION,
|
||||||
btcWalletService.getLastBlockSeenHeight(),
|
btcWalletService.getLastBlockSeenHeight(),
|
||||||
txFeeFromFeeService.value,
|
txFeeToUse.value,
|
||||||
makerFeeAsCoin.value,
|
makerFeeAsCoin.value,
|
||||||
isCurrencyForMakerFeeBtc,
|
isCurrencyForMakerFeeBtc,
|
||||||
buyerSecurityDepositAsCoin.value,
|
buyerSecurityDepositAsCoin.value,
|
||||||
|
@ -365,6 +365,14 @@ public class Offer implements NetworkPayload, PersistablePayload {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getPaymentMethodNameWithCountryCode() {
|
||||||
|
String method = this.getPaymentMethod().getShortName();
|
||||||
|
String methodCountryCode = this.getCountryCode();
|
||||||
|
if (methodCountryCode != null)
|
||||||
|
method = method + " (" + methodCountryCode + ")";
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
// domain properties
|
// domain properties
|
||||||
public Offer.State getState() {
|
public Offer.State getState() {
|
||||||
return stateProperty.get();
|
return stateProperty.get();
|
||||||
|
@ -23,6 +23,7 @@ import bisq.core.btc.wallet.TradeWalletService;
|
|||||||
import bisq.core.dao.DaoFacade;
|
import bisq.core.dao.DaoFacade;
|
||||||
import bisq.core.exceptions.TradePriceOutOfToleranceException;
|
import bisq.core.exceptions.TradePriceOutOfToleranceException;
|
||||||
import bisq.core.locale.Res;
|
import bisq.core.locale.Res;
|
||||||
|
import bisq.core.filter.FilterManager;
|
||||||
import bisq.core.offer.availability.DisputeAgentSelection;
|
import bisq.core.offer.availability.DisputeAgentSelection;
|
||||||
import bisq.core.offer.messages.OfferAvailabilityRequest;
|
import bisq.core.offer.messages.OfferAvailabilityRequest;
|
||||||
import bisq.core.offer.messages.OfferAvailabilityResponse;
|
import bisq.core.offer.messages.OfferAvailabilityResponse;
|
||||||
@ -111,6 +112,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||||||
private final MediatorManager mediatorManager;
|
private final MediatorManager mediatorManager;
|
||||||
private final RefundAgentManager refundAgentManager;
|
private final RefundAgentManager refundAgentManager;
|
||||||
private final DaoFacade daoFacade;
|
private final DaoFacade daoFacade;
|
||||||
|
private final FilterManager filterManager;
|
||||||
private final Storage<TradableList<OpenOffer>> openOfferTradableListStorage;
|
private final Storage<TradableList<OpenOffer>> openOfferTradableListStorage;
|
||||||
private final Map<String, OpenOffer> offersToBeEdited = new HashMap<>();
|
private final Map<String, OpenOffer> offersToBeEdited = new HashMap<>();
|
||||||
private boolean stopped;
|
private boolean stopped;
|
||||||
@ -139,6 +141,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||||||
MediatorManager mediatorManager,
|
MediatorManager mediatorManager,
|
||||||
RefundAgentManager refundAgentManager,
|
RefundAgentManager refundAgentManager,
|
||||||
DaoFacade daoFacade,
|
DaoFacade daoFacade,
|
||||||
|
FilterManager filterManager,
|
||||||
Storage<TradableList<OpenOffer>> storage) {
|
Storage<TradableList<OpenOffer>> storage) {
|
||||||
this.createOfferService = createOfferService;
|
this.createOfferService = createOfferService;
|
||||||
this.keyRing = keyRing;
|
this.keyRing = keyRing;
|
||||||
@ -156,6 +159,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||||||
this.mediatorManager = mediatorManager;
|
this.mediatorManager = mediatorManager;
|
||||||
this.refundAgentManager = refundAgentManager;
|
this.refundAgentManager = refundAgentManager;
|
||||||
this.daoFacade = daoFacade;
|
this.daoFacade = daoFacade;
|
||||||
|
this.filterManager = filterManager;
|
||||||
|
|
||||||
openOfferTradableListStorage = storage;
|
openOfferTradableListStorage = storage;
|
||||||
|
|
||||||
@ -361,7 +365,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||||||
arbitratorManager,
|
arbitratorManager,
|
||||||
tradeStatisticsManager,
|
tradeStatisticsManager,
|
||||||
daoFacade,
|
daoFacade,
|
||||||
user);
|
user,
|
||||||
|
filterManager);
|
||||||
PlaceOfferProtocol placeOfferProtocol = new PlaceOfferProtocol(
|
PlaceOfferProtocol placeOfferProtocol = new PlaceOfferProtocol(
|
||||||
model,
|
model,
|
||||||
transaction -> {
|
transaction -> {
|
||||||
|
@ -21,6 +21,7 @@ import bisq.core.btc.wallet.BsqWalletService;
|
|||||||
import bisq.core.btc.wallet.BtcWalletService;
|
import bisq.core.btc.wallet.BtcWalletService;
|
||||||
import bisq.core.btc.wallet.TradeWalletService;
|
import bisq.core.btc.wallet.TradeWalletService;
|
||||||
import bisq.core.dao.DaoFacade;
|
import bisq.core.dao.DaoFacade;
|
||||||
|
import bisq.core.filter.FilterManager;
|
||||||
import bisq.core.offer.Offer;
|
import bisq.core.offer.Offer;
|
||||||
import bisq.core.offer.OfferBookService;
|
import bisq.core.offer.OfferBookService;
|
||||||
import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
|
import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
|
||||||
@ -51,6 +52,8 @@ public class PlaceOfferModel implements Model {
|
|||||||
private final TradeStatisticsManager tradeStatisticsManager;
|
private final TradeStatisticsManager tradeStatisticsManager;
|
||||||
private final DaoFacade daoFacade;
|
private final DaoFacade daoFacade;
|
||||||
private final User user;
|
private final User user;
|
||||||
|
@Getter
|
||||||
|
private final FilterManager filterManager;
|
||||||
|
|
||||||
// Mutable
|
// Mutable
|
||||||
@Setter
|
@Setter
|
||||||
@ -68,7 +71,8 @@ public class PlaceOfferModel implements Model {
|
|||||||
ArbitratorManager arbitratorManager,
|
ArbitratorManager arbitratorManager,
|
||||||
TradeStatisticsManager tradeStatisticsManager,
|
TradeStatisticsManager tradeStatisticsManager,
|
||||||
DaoFacade daoFacade,
|
DaoFacade daoFacade,
|
||||||
User user) {
|
User user,
|
||||||
|
FilterManager filterManager) {
|
||||||
this.offer = offer;
|
this.offer = offer;
|
||||||
this.reservedFundsForOffer = reservedFundsForOffer;
|
this.reservedFundsForOffer = reservedFundsForOffer;
|
||||||
this.useSavingsWallet = useSavingsWallet;
|
this.useSavingsWallet = useSavingsWallet;
|
||||||
@ -80,6 +84,7 @@ public class PlaceOfferModel implements Model {
|
|||||||
this.tradeStatisticsManager = tradeStatisticsManager;
|
this.tradeStatisticsManager = tradeStatisticsManager;
|
||||||
this.daoFacade = daoFacade;
|
this.daoFacade = daoFacade;
|
||||||
this.user = user;
|
this.user = user;
|
||||||
|
this.filterManager = filterManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -25,10 +25,10 @@ import bisq.core.btc.wallet.TradeWalletService;
|
|||||||
import bisq.core.btc.wallet.TxBroadcaster;
|
import bisq.core.btc.wallet.TxBroadcaster;
|
||||||
import bisq.core.btc.wallet.WalletService;
|
import bisq.core.btc.wallet.WalletService;
|
||||||
import bisq.core.dao.exceptions.DaoDisabledException;
|
import bisq.core.dao.exceptions.DaoDisabledException;
|
||||||
import bisq.core.dao.governance.param.Param;
|
|
||||||
import bisq.core.dao.state.model.blockchain.TxType;
|
import bisq.core.dao.state.model.blockchain.TxType;
|
||||||
import bisq.core.offer.Offer;
|
import bisq.core.offer.Offer;
|
||||||
import bisq.core.offer.placeoffer.PlaceOfferModel;
|
import bisq.core.offer.placeoffer.PlaceOfferModel;
|
||||||
|
import bisq.core.util.FeeReceiverSelector;
|
||||||
|
|
||||||
import bisq.common.UserThread;
|
import bisq.common.UserThread;
|
||||||
import bisq.common.taskrunner.Task;
|
import bisq.common.taskrunner.Task;
|
||||||
@ -65,7 +65,8 @@ public class CreateMakerFeeTx extends Task<PlaceOfferModel> {
|
|||||||
Address changeAddress = walletService.getFreshAddressEntry().getAddress();
|
Address changeAddress = walletService.getFreshAddressEntry().getAddress();
|
||||||
|
|
||||||
TradeWalletService tradeWalletService = model.getTradeWalletService();
|
TradeWalletService tradeWalletService = model.getTradeWalletService();
|
||||||
String feeReceiver = model.getDaoFacade().getParamValue(Param.RECIPIENT_BTC_ADDRESS);
|
|
||||||
|
String feeReceiver = FeeReceiverSelector.getAddress(model.getDaoFacade(), model.getFilterManager());
|
||||||
|
|
||||||
if (offer.isCurrencyForMakerFeeBtc()) {
|
if (offer.isCurrencyForMakerFeeBtc()) {
|
||||||
tradeWalletService.createBtcTradingFeeTx(
|
tradeWalletService.createBtcTradingFeeTx(
|
||||||
|
@ -169,4 +169,8 @@ public abstract class PaymentAccount implements PersistablePayload {
|
|||||||
public String getSaltAsHex() {
|
public String getSaltAsHex() {
|
||||||
return Utilities.bytesAsHexString(getSalt());
|
return Utilities.bytesAsHexString(getSalt());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getOwnerId() {
|
||||||
|
return paymentAccountPayload.getOwnerId();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,4 +179,9 @@ public abstract class BankAccountPayload extends CountryBasedPaymentAccountPaylo
|
|||||||
|
|
||||||
return super.getAgeWitnessInputData(all.getBytes(StandardCharsets.UTF_8));
|
return super.getAgeWitnessInputData(all.getBytes(StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOwnerId() {
|
||||||
|
return holderName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -224,4 +224,9 @@ public class CashDepositAccountPayload extends CountryBasedPaymentAccountPayload
|
|||||||
|
|
||||||
return super.getAgeWitnessInputData(all.getBytes(StandardCharsets.UTF_8));
|
return super.getAgeWitnessInputData(all.getBytes(StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOwnerId() {
|
||||||
|
return holderName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,4 +106,9 @@ public final class ChaseQuickPayAccountPayload extends PaymentAccountPayload {
|
|||||||
// slight changes in holder name (e.g. add or remove middle name)
|
// slight changes in holder name (e.g. add or remove middle name)
|
||||||
return super.getAgeWitnessInputData(email.getBytes(StandardCharsets.UTF_8));
|
return super.getAgeWitnessInputData(email.getBytes(StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOwnerId() {
|
||||||
|
return holderName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,4 +106,9 @@ public final class ClearXchangeAccountPayload extends PaymentAccountPayload {
|
|||||||
// slight changes in holder name (e.g. add or remove middle name)
|
// slight changes in holder name (e.g. add or remove middle name)
|
||||||
return super.getAgeWitnessInputData(emailOrMobileNr.getBytes(StandardCharsets.UTF_8));
|
return super.getAgeWitnessInputData(emailOrMobileNr.getBytes(StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOwnerId() {
|
||||||
|
return holderName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,4 +120,9 @@ public final class InteracETransferAccountPayload extends PaymentAccountPayload
|
|||||||
ArrayUtils.addAll(question.getBytes(StandardCharsets.UTF_8),
|
ArrayUtils.addAll(question.getBytes(StandardCharsets.UTF_8),
|
||||||
answer.getBytes(StandardCharsets.UTF_8))));
|
answer.getBytes(StandardCharsets.UTF_8))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOwnerId() {
|
||||||
|
return holderName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,4 +135,8 @@ public abstract class PaymentAccountPayload implements NetworkPayload, UsedForTr
|
|||||||
protected byte[] getAgeWitnessInputData(byte[] data) {
|
protected byte[] getAgeWitnessInputData(byte[] data) {
|
||||||
return ArrayUtils.addAll(paymentMethodId.getBytes(StandardCharsets.UTF_8), data);
|
return ArrayUtils.addAll(paymentMethodId.getBytes(StandardCharsets.UTF_8), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getOwnerId() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,6 +313,12 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme
|
|||||||
return Coin.valueOf(tradeLimits.getRoundedRiskBasedTradeLimit(maxTradeLimit, riskFactor));
|
return Coin.valueOf(tradeLimits.getRoundedRiskBasedTradeLimit(maxTradeLimit, riskFactor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getShortName() {
|
||||||
|
// in cases where translation is not found, Res.get() simply returns the key string
|
||||||
|
// so no need for special error-handling code.
|
||||||
|
return Res.get(this.id + "_SHORT");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(@NotNull PaymentMethod other) {
|
public int compareTo(@NotNull PaymentMethod other) {
|
||||||
return id.compareTo(other.id);
|
return id.compareTo(other.id);
|
||||||
|
@ -103,4 +103,9 @@ public final class PopmoneyAccountPayload extends PaymentAccountPayload {
|
|||||||
public byte[] getAgeWitnessInputData() {
|
public byte[] getAgeWitnessInputData() {
|
||||||
return super.getAgeWitnessInputData(accountId.getBytes(StandardCharsets.UTF_8));
|
return super.getAgeWitnessInputData(accountId.getBytes(StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOwnerId() {
|
||||||
|
return holderName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,4 +158,8 @@ public final class SepaAccountPayload extends CountryBasedPaymentAccountPayload
|
|||||||
// slight changes in holder name (e.g. add or remove middle name)
|
// slight changes in holder name (e.g. add or remove middle name)
|
||||||
return super.getAgeWitnessInputData(ArrayUtils.addAll(iban.getBytes(StandardCharsets.UTF_8), bic.getBytes(StandardCharsets.UTF_8)));
|
return super.getAgeWitnessInputData(ArrayUtils.addAll(iban.getBytes(StandardCharsets.UTF_8), bic.getBytes(StandardCharsets.UTF_8)));
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public String getOwnerId() {
|
||||||
|
return holderName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,4 +153,9 @@ public final class SepaInstantAccountPayload extends CountryBasedPaymentAccountP
|
|||||||
// slight changes in holder name (e.g. add or remove middle name)
|
// slight changes in holder name (e.g. add or remove middle name)
|
||||||
return super.getAgeWitnessInputData(ArrayUtils.addAll(iban.getBytes(StandardCharsets.UTF_8), bic.getBytes(StandardCharsets.UTF_8)));
|
return super.getAgeWitnessInputData(ArrayUtils.addAll(iban.getBytes(StandardCharsets.UTF_8), bic.getBytes(StandardCharsets.UTF_8)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOwnerId() {
|
||||||
|
return holderName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,4 +104,9 @@ public final class SwishAccountPayload extends PaymentAccountPayload {
|
|||||||
// slight changes in holder name (e.g. add or remove middle name)
|
// slight changes in holder name (e.g. add or remove middle name)
|
||||||
return super.getAgeWitnessInputData(mobileNr.getBytes(StandardCharsets.UTF_8));
|
return super.getAgeWitnessInputData(mobileNr.getBytes(StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOwnerId() {
|
||||||
|
return holderName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,4 +107,9 @@ public final class USPostalMoneyOrderAccountPayload extends PaymentAccountPayloa
|
|||||||
return super.getAgeWitnessInputData(ArrayUtils.addAll(holderName.getBytes(StandardCharsets.UTF_8),
|
return super.getAgeWitnessInputData(ArrayUtils.addAll(holderName.getBytes(StandardCharsets.UTF_8),
|
||||||
postalAddress.getBytes(StandardCharsets.UTF_8)));
|
postalAddress.getBytes(StandardCharsets.UTF_8)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOwnerId() {
|
||||||
|
return holderName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,4 +106,9 @@ public final class VenmoAccountPayload extends PaymentAccountPayload {
|
|||||||
public byte[] getAgeWitnessInputData() {
|
public byte[] getAgeWitnessInputData() {
|
||||||
return super.getAgeWitnessInputData(venmoUserName.getBytes(StandardCharsets.UTF_8));
|
return super.getAgeWitnessInputData(venmoUserName.getBytes(StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOwnerId() {
|
||||||
|
return holderName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,9 @@ import bisq.core.btc.wallet.BtcWalletService;
|
|||||||
import bisq.core.btc.wallet.TradeWalletService;
|
import bisq.core.btc.wallet.TradeWalletService;
|
||||||
import bisq.core.btc.wallet.WalletService;
|
import bisq.core.btc.wallet.WalletService;
|
||||||
import bisq.core.dao.exceptions.DaoDisabledException;
|
import bisq.core.dao.exceptions.DaoDisabledException;
|
||||||
import bisq.core.dao.governance.param.Param;
|
|
||||||
import bisq.core.trade.Trade;
|
import bisq.core.trade.Trade;
|
||||||
import bisq.core.trade.protocol.tasks.TradeTask;
|
import bisq.core.trade.protocol.tasks.TradeTask;
|
||||||
|
import bisq.core.util.FeeReceiverSelector;
|
||||||
|
|
||||||
import bisq.common.taskrunner.TaskRunner;
|
import bisq.common.taskrunner.TaskRunner;
|
||||||
|
|
||||||
@ -65,7 +65,9 @@ public class CreateTakerFeeTx extends TradeTask {
|
|||||||
Address changeAddress = changeAddressEntry.getAddress();
|
Address changeAddress = changeAddressEntry.getAddress();
|
||||||
TradeWalletService tradeWalletService = processModel.getTradeWalletService();
|
TradeWalletService tradeWalletService = processModel.getTradeWalletService();
|
||||||
Transaction transaction;
|
Transaction transaction;
|
||||||
String feeReceiver = processModel.getDaoFacade().getParamValue(Param.RECIPIENT_BTC_ADDRESS);
|
|
||||||
|
String feeReceiver = FeeReceiverSelector.getAddress(processModel.getDaoFacade(), processModel.getFilterManager());
|
||||||
|
|
||||||
if (trade.isCurrencyForTakerFeeBtc()) {
|
if (trade.isCurrencyForTakerFeeBtc()) {
|
||||||
transaction = tradeWalletService.createBtcTradingFeeTx(
|
transaction = tradeWalletService.createBtcTradingFeeTx(
|
||||||
fundingAddress,
|
fundingAddress,
|
||||||
|
@ -78,10 +78,12 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||||||
public final class Preferences implements PersistedDataHost, BridgeAddressProvider {
|
public final class Preferences implements PersistedDataHost, BridgeAddressProvider {
|
||||||
|
|
||||||
private static final ArrayList<BlockChainExplorer> BTC_MAIN_NET_EXPLORERS = new ArrayList<>(Arrays.asList(
|
private static final ArrayList<BlockChainExplorer> BTC_MAIN_NET_EXPLORERS = new ArrayList<>(Arrays.asList(
|
||||||
|
new BlockChainExplorer("mempool.space (@wiz)", "https://mempool.space/tx/", "https://mempool.space/address/"),
|
||||||
|
new BlockChainExplorer("mempool.space Tor V3", "http://mempoolhqx4isw62xs7abwphsq7ldayuidyx2v2oethdhhj6mlo2r6ad.onion/tx/", "http://mempoolhqx4isw62xs7abwphsq7ldayuidyx2v2oethdhhj6mlo2r6ad.onion/address/"),
|
||||||
|
new BlockChainExplorer("mempool.emzy.de (@emzy)", "https://mempool.emzy.de/tx/", "https://mempool.emzy.de/address/"),
|
||||||
|
new BlockChainExplorer("mempool.emzy.de Tor V3", "http://mempool4t6mypeemozyterviq3i5de4kpoua65r3qkn5i3kknu5l2cad.onion/tx/", "http://mempool4t6mypeemozyterviq3i5de4kpoua65r3qkn5i3kknu5l2cad.onion/address/"),
|
||||||
new BlockChainExplorer("Blockstream.info", "https://blockstream.info/tx/", "https://blockstream.info/address/"),
|
new BlockChainExplorer("Blockstream.info", "https://blockstream.info/tx/", "https://blockstream.info/address/"),
|
||||||
new BlockChainExplorer("Blockstream.info Tor V3", "http://explorerzydxu5ecjrkwceayqybizmpjjznk5izmitf2modhcusuqlid.onion/tx/", "http://explorerzydxu5ecjrkwceayqybizmpjjznk5izmitf2modhcusuqlid.onion/address/"),
|
new BlockChainExplorer("Blockstream.info Tor V3", "http://explorerzydxu5ecjrkwceayqybizmpjjznk5izmitf2modhcusuqlid.onion/tx/", "http://explorerzydxu5ecjrkwceayqybizmpjjznk5izmitf2modhcusuqlid.onion/address/"),
|
||||||
new BlockChainExplorer("mempool.ninja", "https://mempool.ninja/tx/", "https://mempool.ninja/address/"),
|
|
||||||
new BlockChainExplorer("mempool.ninja Tor V2", "http://mempooltxrqf4re5.onion/tx/", "http://mempooltxrqf4re5.onion/address/"),
|
|
||||||
new BlockChainExplorer("OXT", "https://oxt.me/transaction/", "https://oxt.me/address/"),
|
new BlockChainExplorer("OXT", "https://oxt.me/transaction/", "https://oxt.me/address/"),
|
||||||
new BlockChainExplorer("Bitaps", "https://bitaps.com/", "https://bitaps.com/"),
|
new BlockChainExplorer("Bitaps", "https://bitaps.com/", "https://bitaps.com/"),
|
||||||
new BlockChainExplorer("Blockcypher", "https://live.blockcypher.com/btc/tx/", "https://live.blockcypher.com/btc/address/"),
|
new BlockChainExplorer("Blockcypher", "https://live.blockcypher.com/btc/tx/", "https://live.blockcypher.com/btc/address/"),
|
||||||
@ -92,7 +94,8 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
|
|||||||
new BlockChainExplorer("Smartbit", "https://www.smartbit.com.au/tx/", "https://www.smartbit.com.au/address/"),
|
new BlockChainExplorer("Smartbit", "https://www.smartbit.com.au/tx/", "https://www.smartbit.com.au/address/"),
|
||||||
new BlockChainExplorer("SoChain. Wow.", "https://chain.so/tx/BTC/", "https://chain.so/address/BTC/"),
|
new BlockChainExplorer("SoChain. Wow.", "https://chain.so/tx/BTC/", "https://chain.so/address/BTC/"),
|
||||||
new BlockChainExplorer("Blockchain.info", "https://blockchain.info/tx/", "https://blockchain.info/address/"),
|
new BlockChainExplorer("Blockchain.info", "https://blockchain.info/tx/", "https://blockchain.info/address/"),
|
||||||
new BlockChainExplorer("Insight", "https://insight.bitpay.com/tx/", "https://insight.bitpay.com/address/")
|
new BlockChainExplorer("Insight", "https://insight.bitpay.com/tx/", "https://insight.bitpay.com/address/"),
|
||||||
|
new BlockChainExplorer("Blockchair", "https://blockchair.com/bitcoin/transaction/", "https://blockchair.com/bitcoin/address/")
|
||||||
));
|
));
|
||||||
private static final ArrayList<BlockChainExplorer> BTC_TEST_NET_EXPLORERS = new ArrayList<>(Arrays.asList(
|
private static final ArrayList<BlockChainExplorer> BTC_TEST_NET_EXPLORERS = new ArrayList<>(Arrays.asList(
|
||||||
new BlockChainExplorer("Blockstream.info", "https://blockstream.info/testnet/tx/", "https://blockstream.info/testnet/address/"),
|
new BlockChainExplorer("Blockstream.info", "https://blockstream.info/testnet/tx/", "https://blockstream.info/testnet/address/"),
|
||||||
@ -101,7 +104,8 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
|
|||||||
new BlockChainExplorer("Blocktrail", "https://www.blocktrail.com/tBTC/tx/", "https://www.blocktrail.com/tBTC/address/"),
|
new BlockChainExplorer("Blocktrail", "https://www.blocktrail.com/tBTC/tx/", "https://www.blocktrail.com/tBTC/address/"),
|
||||||
new BlockChainExplorer("Biteasy", "https://www.biteasy.com/testnet/transactions/", "https://www.biteasy.com/testnet/addresses/"),
|
new BlockChainExplorer("Biteasy", "https://www.biteasy.com/testnet/transactions/", "https://www.biteasy.com/testnet/addresses/"),
|
||||||
new BlockChainExplorer("Smartbit", "https://testnet.smartbit.com.au/tx/", "https://testnet.smartbit.com.au/address/"),
|
new BlockChainExplorer("Smartbit", "https://testnet.smartbit.com.au/tx/", "https://testnet.smartbit.com.au/address/"),
|
||||||
new BlockChainExplorer("SoChain. Wow.", "https://chain.so/tx/BTCTEST/", "https://chain.so/address/BTCTEST/")
|
new BlockChainExplorer("SoChain. Wow.", "https://chain.so/tx/BTCTEST/", "https://chain.so/address/BTCTEST/"),
|
||||||
|
new BlockChainExplorer("Blockchair", "https://blockchair.com/bitcoin/testnet/transaction/", "https://blockchair.com/bitcoin/testnet/address/")
|
||||||
));
|
));
|
||||||
private static final ArrayList<BlockChainExplorer> BTC_DAO_TEST_NET_EXPLORERS = new ArrayList<>(Collections.singletonList(
|
private static final ArrayList<BlockChainExplorer> BTC_DAO_TEST_NET_EXPLORERS = new ArrayList<>(Collections.singletonList(
|
||||||
new BlockChainExplorer("BTC DAO-testnet explorer", "https://bisq.network/explorer/btc/dao_testnet/tx/", "https://bisq.network/explorer/btc/dao_testnet/address/")
|
new BlockChainExplorer("BTC DAO-testnet explorer", "https://bisq.network/explorer/btc/dao_testnet/tx/", "https://bisq.network/explorer/btc/dao_testnet/address/")
|
||||||
|
78
core/src/main/java/bisq/core/util/FeeReceiverSelector.java
Normal file
78
core/src/main/java/bisq/core/util/FeeReceiverSelector.java
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
import bisq.core.dao.DaoFacade;
|
||||||
|
import bisq.core.dao.governance.param.Param;
|
||||||
|
import bisq.core.filter.FilterManager;
|
||||||
|
|
||||||
|
import org.bitcoinj.core.Coin;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class FeeReceiverSelector {
|
||||||
|
public static String getAddress(DaoFacade daoFacade, FilterManager filterManager) {
|
||||||
|
return getAddress(daoFacade, filterManager, new Random());
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
static String getAddress(DaoFacade daoFacade, FilterManager filterManager, Random rnd) {
|
||||||
|
List<String> feeReceivers = Optional.ofNullable(filterManager.getFilter())
|
||||||
|
.flatMap(f -> Optional.ofNullable(f.getBtcFeeReceiverAddresses()))
|
||||||
|
.orElse(List.of());
|
||||||
|
|
||||||
|
List<Long> amountList = new ArrayList<>();
|
||||||
|
List<String> receiverAddressList = new ArrayList<>();
|
||||||
|
|
||||||
|
feeReceivers.forEach(e -> {
|
||||||
|
try {
|
||||||
|
String[] tokens = e.split("#");
|
||||||
|
amountList.add(Coin.parseCoin(tokens[1]).longValue()); // total amount the victim should receive
|
||||||
|
receiverAddressList.add(tokens[0]); // victim's receiver address
|
||||||
|
} catch (RuntimeException ignore) {
|
||||||
|
// If input format is not as expected we ignore entry
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!amountList.isEmpty()) {
|
||||||
|
return receiverAddressList.get(weightedSelection(amountList, rnd));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We keep default value as fallback in case no filter value is available or user has old version.
|
||||||
|
return daoFacade.getParamValue(Param.RECIPIENT_BTC_ADDRESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
static int weightedSelection(List<Long> weights, Random rnd) {
|
||||||
|
long sum = weights.stream().mapToLong(n -> n).sum();
|
||||||
|
long target = rnd.longs(0, sum).findFirst().orElseThrow();
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < weights.size() && target >= 0; i++) {
|
||||||
|
target -= weights.get(i);
|
||||||
|
}
|
||||||
|
return i - 1;
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,12 @@
|
|||||||
# nodeaddress.onion:port [(@owner,@backup)]
|
# nodeaddress.onion:port [(@owner,@backup)]
|
||||||
5quyxpxheyvzmb2d.onion:8000 (@miker)
|
5quyxpxheyvzmb2d.onion:8000 (@miker)
|
||||||
s67qglwhkgkyvr74.onion:8000 (@emzy)
|
s67qglwhkgkyvr74.onion:8000 (@emzy)
|
||||||
ef5qnzx6znifo3df.onion:8000 (@wiz,@emzy)
|
|
||||||
3f3cu2yw7u457ztq.onion:8000 (@devinbileck,@ripcurlx)
|
3f3cu2yw7u457ztq.onion:8000 (@devinbileck,@ripcurlx)
|
||||||
723ljisnynbtdohi.onion:8000 (@emzy)
|
723ljisnynbtdohi.onion:8000 (@emzy)
|
||||||
rm7b56wbrcczpjvl.onion:8000 (@miker)
|
rm7b56wbrcczpjvl.onion:8000 (@miker)
|
||||||
fl3mmribyxgrv63c.onion:8000 (@devinbileck,@ripcurlx)
|
fl3mmribyxgrv63c.onion:8000 (@devinbileck,@ripcurlx)
|
||||||
wizseedscybbttk4bmb2lzvbuk2jtect37lcpva4l3twktmkzemwbead.onion:8000 (@wiz)
|
wizseedscybbttk4bmb2lzvbuk2jtect37lcpva4l3twktmkzemwbead.onion:8000 (@wiz)
|
||||||
|
wizseed3d376esppbmbjxk2fhk2jg5fpucddrzj2kxtbxbx4vrnwclad.onion:8000 (@wiz)
|
||||||
|
wizseed7ab2gi3x267xahrp2pkndyrovczezzb46jk6quvguciuyqrid.onion:8000 (@wiz)
|
||||||
|
devinv3rhon24gqf5v6ondoqgyrbzyqihzyouzv7ptltsewhfmox2zqd.onion:8000 (@devinbileck)
|
||||||
|
sn3emzy56u3mxzsr4geysc52feoq5qt7ja56km6gygwnszkshunn2sid.onion:8000 (@emzy)
|
||||||
|
@ -747,7 +747,7 @@ portfolio.pending.step5_buyer.refunded=Refunded security deposit
|
|||||||
portfolio.pending.step5_buyer.withdrawBTC=Withdraw your bitcoin
|
portfolio.pending.step5_buyer.withdrawBTC=Withdraw your bitcoin
|
||||||
portfolio.pending.step5_buyer.amount=Amount to withdraw
|
portfolio.pending.step5_buyer.amount=Amount to withdraw
|
||||||
portfolio.pending.step5_buyer.withdrawToAddress=Withdraw to address
|
portfolio.pending.step5_buyer.withdrawToAddress=Withdraw to address
|
||||||
portfolio.pending.step5_buyer.moveToBisqWallet=Move funds to Bisq wallet
|
portfolio.pending.step5_buyer.moveToBisqWallet=Keep funds in Bisq wallet
|
||||||
portfolio.pending.step5_buyer.withdrawExternal=Withdraw to external wallet
|
portfolio.pending.step5_buyer.withdrawExternal=Withdraw to external wallet
|
||||||
portfolio.pending.step5_buyer.alreadyWithdrawn=Your funds have already been withdrawn.\nPlease check the transaction history.
|
portfolio.pending.step5_buyer.alreadyWithdrawn=Your funds have already been withdrawn.\nPlease check the transaction history.
|
||||||
portfolio.pending.step5_buyer.confirmWithdrawal=Confirm withdrawal request
|
portfolio.pending.step5_buyer.confirmWithdrawal=Confirm withdrawal request
|
||||||
@ -2429,6 +2429,7 @@ filterWindow.disableDaoBelowVersion=Min. version required for DAO
|
|||||||
filterWindow.disableTradeBelowVersion=Min. version required for trading
|
filterWindow.disableTradeBelowVersion=Min. version required for trading
|
||||||
filterWindow.add=Add filter
|
filterWindow.add=Add filter
|
||||||
filterWindow.remove=Remove filter
|
filterWindow.remove=Remove filter
|
||||||
|
filterWindow.btcFeeReceiverAddresses=BTC fee receiver addresses
|
||||||
|
|
||||||
offerDetailsWindow.minBtcAmount=Min. BTC amount
|
offerDetailsWindow.minBtcAmount=Min. BTC amount
|
||||||
offerDetailsWindow.min=(min. {0})
|
offerDetailsWindow.min=(min. {0})
|
||||||
@ -2952,6 +2953,10 @@ seed.warn.walletNotEmpty.emptyWallet=I will empty my wallets first
|
|||||||
seed.warn.notEncryptedAnymore=Your wallets are encrypted.\n\n\
|
seed.warn.notEncryptedAnymore=Your wallets are encrypted.\n\n\
|
||||||
After restore, the wallets will no longer be encrypted and you must set a new password.\n\n\
|
After restore, the wallets will no longer be encrypted and you must set a new password.\n\n\
|
||||||
Do you want to proceed?
|
Do you want to proceed?
|
||||||
|
seed.warn.walletDateEmpty=As you have not specified a wallet date, bisq will have to scan the blockchain from 2013.10.09 (the BIP39 epoch date).\n\n\
|
||||||
|
BIP39 wallets were first introduced in bisq on 2017.06.28 (release v0.5). So you could save time by using that date.\n\n\
|
||||||
|
Ideally you should specify the date your wallet seed was created.\n\n\n\
|
||||||
|
Are you sure you want to go ahead without specifying a wallet date?
|
||||||
seed.restore.success=Wallets restored successfully with the new seed words.\n\nYou need to shut down and restart the application.
|
seed.restore.success=Wallets restored successfully with the new seed words.\n\nYou need to shut down and restart the application.
|
||||||
seed.restore.error=An error occurred when restoring the wallets with seed words.{0}
|
seed.restore.error=An error occurred when restoring the wallets with seed words.{0}
|
||||||
|
|
||||||
@ -3039,27 +3044,14 @@ payment.accountType=Account type
|
|||||||
payment.checking=Checking
|
payment.checking=Checking
|
||||||
payment.savings=Savings
|
payment.savings=Savings
|
||||||
payment.personalId=Personal ID
|
payment.personalId=Personal ID
|
||||||
payment.clearXchange.info=Please be sure that you fulfill the requirements for the usage of Zelle (ClearXchange).\n\n\
|
payment.clearXchange.info=Zelle is a money transfer service that works best *through* another bank.\n\n\
|
||||||
1. You need to have your Zelle (ClearXchange) account verified on their platform \
|
1. Check this page to see if (and how) your bank works with Zelle:\nhttps://www.zellepay.com/get-started\n\n\
|
||||||
before starting a trade or creating an offer.\n\n\
|
2. Take special note of your transfer limits—sending limits vary by bank, and banks often specify separate daily, weekly, and monthly limits.\n\n\
|
||||||
2. You need to have a bank account at one of the following member banks:\n\
|
3. If your bank does not work with Zelle, you can still use it through the Zelle mobile app, but your transfer limits will be much lower.\n\n\
|
||||||
\t● Bank of America\n\
|
4. The name specified on your Bisq account MUST match the name on your Zelle/bank account. \n\n\
|
||||||
\t● Capital One P2P Payments\n\
|
If you cannot complete a Zelle transaction as specified in your trade contract, you may lose some (or all) of your security deposit.\n\n\
|
||||||
\t● Chase QuickPay\n\
|
Because of Zelle''s somewhat higher chargeback risk, sellers are advised to contact unsigned buyers through email or SMS to verify that the buyer \
|
||||||
\t● FirstBank Person to Person Transfers\n\
|
really owns the Zelle account specified in Bisq.
|
||||||
\t● Frost Send Money\n\
|
|
||||||
\t● U.S. Bank Send Money\n\
|
|
||||||
\t● TD Bank\n\
|
|
||||||
\t● Citibank\n\
|
|
||||||
\t● Wells Fargo SurePay\n\n\
|
|
||||||
3. You need to be sure to not exceed the daily or monthly Zelle (ClearXchange) transfer limits.\n\n\
|
|
||||||
Please use Zelle (ClearXchange) only if you fulfill all those requirements, \
|
|
||||||
otherwise it is very likely that the Zelle (ClearXchange) transfer fails and the trade ends up in a dispute.\n\
|
|
||||||
If you have not fulfilled the above requirements you will lose your security deposit.\n\n\
|
|
||||||
Please also be aware of a higher chargeback risk when using Zelle (ClearXchange).\n\
|
|
||||||
For the {0} seller it is highly recommended \
|
|
||||||
to get in contact with the {1} buyer by using the provided email address or mobile number to verify that he or she \
|
|
||||||
is really the owner of the Zelle (ClearXchange) account.
|
|
||||||
payment.fasterPayments.newRequirements.info=Some banks have started verifying the receiver''s full name for Faster \
|
payment.fasterPayments.newRequirements.info=Some banks have started verifying the receiver''s full name for Faster \
|
||||||
Payments transfers. Your current Faster Payments account does not specify a full name.\n\n\
|
Payments transfers. Your current Faster Payments account does not specify a full name.\n\n\
|
||||||
Please consider recreating your Faster Payments account in Bisq to provide future {0} buyers with a full name.\n\n\
|
Please consider recreating your Faster Payments account in Bisq to provide future {0} buyers with a full name.\n\n\
|
||||||
@ -3086,29 +3078,31 @@ payment.limits.info=Please be aware that all bank transfers carry a certain amou
|
|||||||
1. The estimated level of chargeback risk for the payment method used\n\
|
1. The estimated level of chargeback risk for the payment method used\n\
|
||||||
2. The age of your account for that payment method\n\
|
2. The age of your account for that payment method\n\
|
||||||
\n\
|
\n\
|
||||||
The account you are creating now is new and its age is zero. As your account grows in age over a two-month period, your per-trade limits will grow along with it:\n\
|
The account you are creating now is new and its age is zero. As your account ages, your per-trade limits will grow:\n\
|
||||||
\n\
|
\n\
|
||||||
● During the 1st month, your per-trade limit will be {0}\n\
|
● During the 1st month, your per-trade limit will be {0}\n\
|
||||||
● During the 2nd month, your per-trade limit will be {1}\n\
|
● During the 2nd month, your per-trade limit will be {1}\n\
|
||||||
● After the 2nd month, your per-trade limit will be {2}\n\
|
● After the 2nd month, your per-trade limit will be {2}\n\
|
||||||
\n\
|
\n\
|
||||||
Please note that there are no limits on the total number of times you can trade.
|
Please note: limits only apply to trade size. You can place as many trades as you like.
|
||||||
payment.limits.info.withSigning=To limit chargeback risk, Bisq sets per-trade buy limits based on the following 2 factors:\n\
|
payment.limits.info.withSigning=To limit chargeback risk, Bisq sets per-trade limits for this payment account type based \
|
||||||
\n\
|
on the following 2 factors:\n\n\
|
||||||
1. General chargeback risk for the payment method\n\
|
1. General chargeback risk for the payment method\n\
|
||||||
2. Account signing status\n\
|
2. Account signing status\n\
|
||||||
\n\
|
\n\
|
||||||
This payment account you just created carries some chargeback risk and is not yet signed by an arbitrator or trusted peer, \
|
This payment account is not yet signed, so it is limited to buying {0} per trade. \
|
||||||
so it is limited to buying {0} per trade. \
|
After signing, buy limits will increase as follows:\n\
|
||||||
After it is signed, buy limits will increase as follows:\n\
|
|
||||||
\n\
|
\n\
|
||||||
● Before signing, and up to 30 days after signing, your per-trade buy limit will be {0}\n\
|
● Before signing, and for 30 days after signing, your per-trade buy limit will be {0}\n\
|
||||||
● 30 days after signing, your per-trade buy limit will be {1}\n\
|
● 30 days after signing, your per-trade buy limit will be {1}\n\
|
||||||
● 60 days after signing, your per-trade buy limit will be {2}\n\
|
● 60 days after signing, your per-trade buy limit will be {2}\n\
|
||||||
\n\
|
\n\
|
||||||
Sell limits are not affected by account signing, and increase merely as account age increases. More information is at https://docs.bisq.network/payment-methods#account-signing.\n\
|
Sell limits are not affected by account signing, and increase with account age.\n\
|
||||||
\n\
|
\n\
|
||||||
There are no limits on the number of trades you can make.
|
See more:\n\
|
||||||
|
https://bisq.wiki/Account_limits\n\
|
||||||
|
\n\
|
||||||
|
Please note: limits only apply to trade size. You can place as many trades as you like.
|
||||||
|
|
||||||
payment.cashDeposit.info=Please confirm your bank allows you to send cash deposits into other peoples' accounts. \
|
payment.cashDeposit.info=Please confirm your bank allows you to send cash deposits into other peoples' accounts. \
|
||||||
For example, Bank of America and Wells Fargo no longer allow such deposits.
|
For example, Bank of America and Wells Fargo no longer allow such deposits.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
TXT CHECKPOINTS 1
|
TXT CHECKPOINTS 1
|
||||||
0
|
0
|
||||||
310
|
313
|
||||||
AAAAAAAAB+EH4QfhAAAH4AEAAABjl7tqvU/FIcDT9gcbVlA4nwtFUbxAtOawZzBpAAAAAKzkcK7NqciBjI/ldojNKncrWleVSgDfBCCn3VRrbSxXaw5/Sf//AB0z8Bkv
|
AAAAAAAAB+EH4QfhAAAH4AEAAABjl7tqvU/FIcDT9gcbVlA4nwtFUbxAtOawZzBpAAAAAKzkcK7NqciBjI/ldojNKncrWleVSgDfBCCn3VRrbSxXaw5/Sf//AB0z8Bkv
|
||||||
AAAAAAAAD8EPwQ/BAAAPwAEAAADfP83Sx8MZ9RsrnZCvqzAwqB2Ma+ZesNAJrTfwAAAAACwESaNKhvRgz6WuE7UFdFk1xwzfRY/OIdIOPzX5yaAdjnWUSf//AB0GrNq5
|
AAAAAAAAD8EPwQ/BAAAPwAEAAADfP83Sx8MZ9RsrnZCvqzAwqB2Ma+ZesNAJrTfwAAAAACwESaNKhvRgz6WuE7UFdFk1xwzfRY/OIdIOPzX5yaAdjnWUSf//AB0GrNq5
|
||||||
AAAAAAAAF6EXoRehAAAXoAEAAADonWzAaUAKd30XT3NnHKobZMnLOuHdzm/xtehsAAAAAD8cUJA6NBIHHcqPHLc4IrfHw+6mjCGu3e+wRO81EvpnMVqrSf//AB1ffy8G
|
AAAAAAAAF6EXoRehAAAXoAEAAADonWzAaUAKd30XT3NnHKobZMnLOuHdzm/xtehsAAAAAD8cUJA6NBIHHcqPHLc4IrfHw+6mjCGu3e+wRO81EvpnMVqrSf//AB1ffy8G
|
||||||
@ -311,3 +311,6 @@ DQOCnM/692T/c/vpAAlxoAAgACBpKU8xBXETUdlfq3ziC5HqY2sbxpLaBgAAAAAAAAAAAC2Podb2UVE3
|
|||||||
DXJv6TyZC6dJNCJfAAl5gAAAwCC821K+00n7cVERL9d6Jzo0wkE8NSY/BAAAAAAAAAAAANEvjjQwmKBYHwf7qsdzHSrM+7AC4wGhHxMBliBwDnPi7SJmXhkBERcyCjYC
|
DXJv6TyZC6dJNCJfAAl5gAAAwCC821K+00n7cVERL9d6Jzo0wkE8NSY/BAAAAAAAAAAAANEvjjQwmKBYHwf7qsdzHSrM+7AC4wGhHxMBliBwDnPi7SJmXhkBERcyCjYC
|
||||||
Dej8cVmdICmGlGmsAAmBYAAAgCAMNQrVauCVnJhLXbUm+wi+s6FYCIDGCwAAAAAAAAAAAHSgbycFfzUIokW6wOwg6yoHf88c9CrCsoU3LGXqo65Awhh8XkE7FBcTwPq1
|
Dej8cVmdICmGlGmsAAmBYAAAgCAMNQrVauCVnJhLXbUm+wi+s6FYCIDGCwAAAAAAAAAAAHSgbycFfzUIokW6wOwg6yoHf88c9CrCsoU3LGXqo65Awhh8XkE7FBcTwPq1
|
||||||
Dkyiv/CRkmMKmkEzAAmJQADgACBD4xnvCIUw3EDxERdHu3/bAmPjwJ15DAAAAAAAAAAAAHiPGbRWrMMMyL6BA6eaJfNIo5XiUMXo0B7u72S1QqDZLpGNXrwgExchnuav
|
Dkyiv/CRkmMKmkEzAAmJQADgACBD4xnvCIUw3EDxERdHu3/bAmPjwJ15DAAAAAAAAAAAAHiPGbRWrMMMyL6BA6eaJfNIo5XiUMXo0B7u72S1QqDZLpGNXrwgExchnuav
|
||||||
|
DrYJPtE6p0g5WpqUAAmRIAAAACAUOgCoJeMzIDa34vdMEznyR1cSUIbpDQAAAAAAAAAAAKlIg5av2zB0dTVJcJhbennqbQ9kisot+0OheDaM0jzyNJueXjOjEReyl0xD
|
||||||
|
DyhWrFlPqEc/c9+uAAmZAAAgACDcrvMMuRSy9GQxh8BFNt6wIDWYhvU4EQAAAAAAAAAAABVOP5QKoWx9atpYrUh6L+UeYRrgD4sj3ZOBngyn3WuRAeawXjl6EReMHTLH
|
||||||
|
D5uvExILinkBRJMsAAmg4ADg/yfO2pclcPlRE5XVKCPZeF63mn30v+yHDgAAAAAAAAAAAPaDA4g+h9tjjVWtJ587WMHb07Mcfa1BoDJCANQd+z94wJDEXvaXEhf5l8cN
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package bisq.core.offer;
|
package bisq.core.offer;
|
||||||
|
|
||||||
import bisq.core.trade.TradableList;
|
|
||||||
|
|
||||||
import bisq.network.p2p.P2PService;
|
import bisq.network.p2p.P2PService;
|
||||||
import bisq.network.p2p.peers.PeerManager;
|
import bisq.network.p2p.peers.PeerManager;
|
||||||
|
|
||||||
@ -47,7 +45,7 @@ public class OpenOfferManagerTest {
|
|||||||
final OpenOfferManager manager = new OpenOfferManager(null, null, null, p2PService,
|
final OpenOfferManager manager = new OpenOfferManager(null, null, null, p2PService,
|
||||||
null, null, null, offerBookService,
|
null, null, null, offerBookService,
|
||||||
null, null, null,
|
null, null, null,
|
||||||
null, null, null, null, null,
|
null, null, null, null, null, null,
|
||||||
new Storage<>(storageDir, null, corruptedDatabaseFilesHandler));
|
new Storage<>(storageDir, null, corruptedDatabaseFilesHandler));
|
||||||
|
|
||||||
AtomicBoolean startEditOfferSuccessful = new AtomicBoolean(false);
|
AtomicBoolean startEditOfferSuccessful = new AtomicBoolean(false);
|
||||||
@ -83,7 +81,7 @@ public class OpenOfferManagerTest {
|
|||||||
final OpenOfferManager manager = new OpenOfferManager(null, null, null, p2PService,
|
final OpenOfferManager manager = new OpenOfferManager(null, null, null, p2PService,
|
||||||
null, null, null, offerBookService,
|
null, null, null, offerBookService,
|
||||||
null, null, null,
|
null, null, null,
|
||||||
null, null, null, null, null,
|
null, null, null, null, null, null,
|
||||||
new Storage<>(storageDir, null, corruptedDatabaseFilesHandler));
|
new Storage<>(storageDir, null, corruptedDatabaseFilesHandler));
|
||||||
|
|
||||||
AtomicBoolean startEditOfferSuccessful = new AtomicBoolean(false);
|
AtomicBoolean startEditOfferSuccessful = new AtomicBoolean(false);
|
||||||
@ -111,7 +109,7 @@ public class OpenOfferManagerTest {
|
|||||||
final OpenOfferManager manager = new OpenOfferManager(null, null, null, p2PService,
|
final OpenOfferManager manager = new OpenOfferManager(null, null, null, p2PService,
|
||||||
null, null, null, offerBookService,
|
null, null, null, offerBookService,
|
||||||
null, null, null,
|
null, null, null,
|
||||||
null, null, null, null, null,
|
null, null, null, null, null, null,
|
||||||
new Storage<>(storageDir, null, corruptedDatabaseFilesHandler));
|
new Storage<>(storageDir, null, corruptedDatabaseFilesHandler));
|
||||||
|
|
||||||
AtomicBoolean startEditOfferSuccessful = new AtomicBoolean(false);
|
AtomicBoolean startEditOfferSuccessful = new AtomicBoolean(false);
|
||||||
|
@ -27,7 +27,6 @@ import com.google.common.collect.Lists;
|
|||||||
|
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
|
|
||||||
@SuppressWarnings("UnusedAssignment")
|
|
||||||
public class UserPayloadModelVOTest {
|
public class UserPayloadModelVOTest {
|
||||||
@Ignore("TODO InvalidKeySpecException at bisq.common.crypto.Sig.getPublicKeyFromBytes(Sig.java:135)")
|
@Ignore("TODO InvalidKeySpecException at bisq.common.crypto.Sig.getPublicKeyFromBytes(Sig.java:135)")
|
||||||
public void testRoundtrip() {
|
public void testRoundtrip() {
|
||||||
@ -59,6 +58,7 @@ public class UserPayloadModelVOTest {
|
|||||||
null,
|
null,
|
||||||
Lists.newArrayList(),
|
Lists.newArrayList(),
|
||||||
Lists.newArrayList(),
|
Lists.newArrayList(),
|
||||||
|
Lists.newArrayList(),
|
||||||
Lists.newArrayList()));
|
Lists.newArrayList()));
|
||||||
vo.setRegisteredArbitrator(ArbitratorTest.getArbitratorMock());
|
vo.setRegisteredArbitrator(ArbitratorTest.getArbitratorMock());
|
||||||
vo.setRegisteredMediator(MediatorTest.getMediatorMock());
|
vo.setRegisteredMediator(MediatorTest.getMediatorMock());
|
||||||
|
107
core/src/test/java/bisq/core/util/FeeReceiverSelectorTest.java
Normal file
107
core/src/test/java/bisq/core/util/FeeReceiverSelectorTest.java
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
import bisq.core.dao.DaoFacade;
|
||||||
|
import bisq.core.dao.governance.param.Param;
|
||||||
|
import bisq.core.filter.Filter;
|
||||||
|
import bisq.core.filter.FilterManager;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Longs;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class FeeReceiverSelectorTest {
|
||||||
|
@Mock
|
||||||
|
private DaoFacade daoFacade;
|
||||||
|
@Mock
|
||||||
|
private FilterManager filterManager;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAddress() {
|
||||||
|
Random rnd = new Random(123);
|
||||||
|
when(filterManager.getFilter()).thenReturn(filterWithReceivers(
|
||||||
|
List.of("", "foo#0.001", "ill-formed", "bar#0.002", "baz#0.001", "partial#bad")));
|
||||||
|
|
||||||
|
Map<String, Integer> selectionCounts = new HashMap<>();
|
||||||
|
for (int i = 0; i < 400; i++) {
|
||||||
|
String address = FeeReceiverSelector.getAddress(daoFacade, filterManager, rnd);
|
||||||
|
selectionCounts.compute(address, (k, n) -> n != null ? n + 1 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(3, selectionCounts.size());
|
||||||
|
|
||||||
|
// Check within 2 std. of the expected values (95% confidence each):
|
||||||
|
assertEquals(100.0, selectionCounts.get("foo"), 18);
|
||||||
|
assertEquals(200.0, selectionCounts.get("bar"), 20);
|
||||||
|
assertEquals(100.0, selectionCounts.get("baz"), 18);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAddress_noValidReceivers() {
|
||||||
|
when(daoFacade.getParamValue(Param.RECIPIENT_BTC_ADDRESS)).thenReturn("default");
|
||||||
|
|
||||||
|
when(filterManager.getFilter()).thenReturn(null);
|
||||||
|
assertEquals("default", FeeReceiverSelector.getAddress(daoFacade, filterManager));
|
||||||
|
|
||||||
|
when(filterManager.getFilter()).thenReturn(filterWithReceivers(null));
|
||||||
|
assertEquals("default", FeeReceiverSelector.getAddress(daoFacade, filterManager));
|
||||||
|
|
||||||
|
when(filterManager.getFilter()).thenReturn(filterWithReceivers(List.of()));
|
||||||
|
assertEquals("default", FeeReceiverSelector.getAddress(daoFacade, filterManager));
|
||||||
|
|
||||||
|
when(filterManager.getFilter()).thenReturn(filterWithReceivers(List.of("ill-formed")));
|
||||||
|
assertEquals("default", FeeReceiverSelector.getAddress(daoFacade, filterManager));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWeightedSelection() {
|
||||||
|
Random rnd = new Random(456);
|
||||||
|
|
||||||
|
int[] selections = new int[3];
|
||||||
|
for (int i = 0; i < 6000; i++) {
|
||||||
|
selections[FeeReceiverSelector.weightedSelection(Longs.asList(1, 2, 3), rnd)]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check within 2 std. of the expected values (95% confidence each):
|
||||||
|
assertEquals(1000.0, selections[0], 58);
|
||||||
|
assertEquals(2000.0, selections[1], 74);
|
||||||
|
assertEquals(3000.0, selections[2], 78);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Filter filterWithReceivers(List<String> btcFeeReceiverAddresses) {
|
||||||
|
return new Filter(null, null, null, null,
|
||||||
|
null, null, null, null,
|
||||||
|
false, null, false, null,
|
||||||
|
null, null, null, null,
|
||||||
|
btcFeeReceiverAddresses);
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
# pull base image
|
# pull base image
|
||||||
FROM openjdk:8-jdk
|
FROM openjdk:8-jdk
|
||||||
ENV version 1.3.4-SNAPSHOT
|
ENV version 1.3.5-SNAPSHOT
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends openjfx && rm -rf /var/lib/apt/lists/* &&
|
RUN apt-get update && apt-get install -y --no-install-recommends openjfx && rm -rf /var/lib/apt/lists/* &&
|
||||||
apt-get install -y vim fakeroot
|
apt-get install -y vim fakeroot
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
# - Update version below
|
# - Update version below
|
||||||
# - Ensure JAVA_HOME below is pointing to OracleJDK 10 directory
|
# - Ensure JAVA_HOME below is pointing to OracleJDK 10 directory
|
||||||
|
|
||||||
version=1.3.4-SNAPSHOT
|
version=1.3.5-SNAPSHOT
|
||||||
version_base=$(echo $version | awk -F'[_-]' '{print $1}')
|
version_base=$(echo $version | awk -F'[_-]' '{print $1}')
|
||||||
if [ ! -f "$JAVA_HOME/bin/javapackager" ]; then
|
if [ ! -f "$JAVA_HOME/bin/javapackager" ]; then
|
||||||
if [ -d "/usr/lib/jvm/jdk-10.0.2" ]; then
|
if [ -d "/usr/lib/jvm/jdk-10.0.2" ]; then
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
# Prior to running this script:
|
# Prior to running this script:
|
||||||
# - Update version below
|
# - Update version below
|
||||||
|
|
||||||
version=1.3.4-SNAPSHOT
|
version=1.3.5-SNAPSHOT
|
||||||
base_dir=$( cd "$(dirname "$0")" ; pwd -P )/../../..
|
base_dir=$( cd "$(dirname "$0")" ; pwd -P )/../../..
|
||||||
package_dir=$base_dir/desktop/package
|
package_dir=$base_dir/desktop/package
|
||||||
release_dir=$base_dir/desktop/release/$version
|
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 -->
|
<!-- See: https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -->
|
||||||
|
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1.3.4</string>
|
<string>1.3.5</string>
|
||||||
|
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.3.4</string>
|
<string>1.3.5</string>
|
||||||
|
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>Bisq</string>
|
<string>Bisq</string>
|
||||||
@ -26,7 +26,7 @@
|
|||||||
<string>public.app-category.finance</string>
|
<string>public.app-category.finance</string>
|
||||||
|
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
<string>Copyright © 2013-2019 - The Bisq developers</string>
|
<string>Copyright © 2013-2020 - The Bisq developers</string>
|
||||||
|
|
||||||
<!-- Only supported in older OSX versions.
|
<!-- Only supported in older OSX versions.
|
||||||
See: https://github.com/bitcoin/bitcoin/issues/11896#issuecomment-352148399-->
|
See: https://github.com/bitcoin/bitcoin/issues/11896#issuecomment-352148399-->
|
||||||
|
@ -6,7 +6,7 @@ mkdir -p deploy
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
version="1.3.4-SNAPSHOT"
|
version="1.3.5-SNAPSHOT"
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
./gradlew :desktop:build -x test shadowJar
|
./gradlew :desktop:build -x test shadowJar
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
cd ../../
|
cd ../../
|
||||||
|
|
||||||
version="1.3.4-SNAPSHOT"
|
version="1.3.5-SNAPSHOT"
|
||||||
|
|
||||||
target_dir="releases/$version"
|
target_dir="releases/$version"
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
cd $(dirname $0)/../../../
|
cd $(dirname $0)/../../../
|
||||||
|
|
||||||
version=1.3.4
|
version=1.3.5
|
||||||
|
|
||||||
find . -type f \( -name "finalize.sh" \
|
find . -type f \( -name "finalize.sh" \
|
||||||
-o -name "create_app.sh" \
|
-o -name "create_app.sh" \
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
cd $(dirname $0)/../../../
|
cd $(dirname $0)/../../../
|
||||||
|
|
||||||
oldVersion=1.3.3
|
oldVersion=1.3.4
|
||||||
newVersion=1.3.4
|
newVersion=1.3.5
|
||||||
|
|
||||||
find . -type f \( -name "finalize.sh" \
|
find . -type f \( -name "finalize.sh" \
|
||||||
-o -name "create_app.sh" \
|
-o -name "create_app.sh" \
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
@echo off
|
@echo off
|
||||||
|
|
||||||
set version=1.3.4-SNAPSHOT
|
set version=1.3.5-SNAPSHOT
|
||||||
if not exist "%JAVA_HOME%\bin\javapackager.exe" (
|
if not exist "%JAVA_HOME%\bin\javapackager.exe" (
|
||||||
if not exist "%ProgramFiles%\Java\jdk-10.0.2" (
|
if not exist "%ProgramFiles%\Java\jdk-10.0.2" (
|
||||||
echo Javapackager not found. Update JAVA_HOME variable to point to OracleJDK.
|
echo Javapackager not found. Update JAVA_HOME variable to point to OracleJDK.
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
@echo off
|
@echo off
|
||||||
|
|
||||||
set version=1.3.4-SNAPSHOT
|
set version=1.3.5-SNAPSHOT
|
||||||
set release_dir=%~dp0..\..\..\releases\%version%
|
set release_dir=%~dp0..\..\..\releases\%version%
|
||||||
set package_dir=%~dp0..
|
set package_dir=%~dp0..
|
||||||
|
|
||||||
|
@ -237,6 +237,30 @@
|
|||||||
-fx-background-color: -fx-selection-bar;
|
-fx-background-color: -fx-selection-bar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* list view */
|
||||||
|
.list-view .list-cell {
|
||||||
|
-fx-background-color: -bs-background-color;
|
||||||
|
}
|
||||||
|
.list-view .list-cell:odd {
|
||||||
|
-fx-background-color: derive(-bs-background-color, -5%);
|
||||||
|
}
|
||||||
|
.list-view .list-cell:even {
|
||||||
|
-fx-background-color: derive(-bs-background-color, 5%);
|
||||||
|
}
|
||||||
|
.list-view .list-cell:hover,
|
||||||
|
.list-view .list-cell:selected,
|
||||||
|
.table-view .table-cell:hover,
|
||||||
|
.table-view .table-cell:selected {
|
||||||
|
-fx-background: -fx-accent;
|
||||||
|
-fx-background-color: -fx-selection-bar;
|
||||||
|
-fx-border-color: -fx-selection-bar;
|
||||||
|
}
|
||||||
|
|
||||||
|
.number-column.table-cell {
|
||||||
|
-fx-background-color: -bs-background-color;
|
||||||
|
}
|
||||||
|
|
||||||
.list-view:focused,
|
.list-view:focused,
|
||||||
.tree-view:focused,
|
.tree-view:focused,
|
||||||
.table-view:focused,
|
.table-view:focused,
|
||||||
@ -867,6 +891,32 @@ textfield */
|
|||||||
* Table *
|
* Table *
|
||||||
* *
|
* *
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
.table-view .table-row-cell:even .table-cell {
|
||||||
|
-fx-background-color: derive(-bs-background-color, 5%);
|
||||||
|
-fx-border-color: derive(-bs-background-color,5%);
|
||||||
|
}
|
||||||
|
.table-view .table-row-cell:odd .table-cell {
|
||||||
|
-fx-background-color: derive(-bs-background-color,-5%);
|
||||||
|
-fx-border-color: derive(-bs-background-color,-5%);
|
||||||
|
}
|
||||||
|
.table-view .table-row-cell:hover .table-cell,
|
||||||
|
.table-view .table-row-cell:selected .table-cell {
|
||||||
|
-fx-background: -fx-accent;
|
||||||
|
-fx-background-color: -fx-selection-bar;
|
||||||
|
-fx-border-color: -fx-selection-bar;
|
||||||
|
}
|
||||||
|
.table-row-cell {
|
||||||
|
-fx-border-color: -bs-background-color;
|
||||||
|
}
|
||||||
|
.table-row-cell:empty, .table-row-cell:empty:even, .table-row-cell:empty:odd {
|
||||||
|
-fx-background-color: -bs-background-color;
|
||||||
|
-fx-min-height: 36;
|
||||||
|
}
|
||||||
|
.offer-table .table-row-cell {
|
||||||
|
-fx-background: -fx-accent;
|
||||||
|
-fx-background-color: -bs-color-gray-6;
|
||||||
|
}
|
||||||
|
|
||||||
.table-view .table-cell {
|
.table-view .table-cell {
|
||||||
-fx-alignment: center-left;
|
-fx-alignment: center-left;
|
||||||
-fx-padding: 2 0 2 0;
|
-fx-padding: 2 0 2 0;
|
||||||
|
@ -147,8 +147,8 @@ public class RevolutForm extends PaymentMethodForm {
|
|||||||
|
|
||||||
private void addCurrenciesGrid(boolean isEditable) {
|
private void addCurrenciesGrid(boolean isEditable) {
|
||||||
FlowPane flowPane = addTopLabelFlowPane(gridPane, ++gridRow,
|
FlowPane flowPane = addTopLabelFlowPane(gridPane, ++gridRow,
|
||||||
Res.get("payment.supportedCurrencies"), Layout.FLOATING_LABEL_DISTANCE,
|
Res.get("payment.supportedCurrencies"), Layout.FLOATING_LABEL_DISTANCE * 3,
|
||||||
Layout.FLOATING_LABEL_DISTANCE).second;
|
Layout.FLOATING_LABEL_DISTANCE * 3).second;
|
||||||
|
|
||||||
if (isEditable)
|
if (isEditable)
|
||||||
flowPane.setId("flow-pane-checkboxes-bg");
|
flowPane.setId("flow-pane-checkboxes-bg");
|
||||||
|
@ -130,6 +130,7 @@ class FiatAccountsDataModel extends ActivatableDataModel {
|
|||||||
user.addPaymentAccount(paymentAccount);
|
user.addPaymentAccount(paymentAccount);
|
||||||
|
|
||||||
accountAgeWitnessService.publishMyAccountAgeWitness(paymentAccount.getPaymentAccountPayload());
|
accountAgeWitnessService.publishMyAccountAgeWitness(paymentAccount.getPaymentAccountPayload());
|
||||||
|
accountAgeWitnessService.signSameNameAccounts();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean onDeleteAccount(PaymentAccount paymentAccount) {
|
public boolean onDeleteAccount(PaymentAccount paymentAccount) {
|
||||||
|
@ -239,6 +239,19 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
|
|||||||
private void checkIfEncrypted() {
|
private void checkIfEncrypted() {
|
||||||
if (walletsManager.areWalletsEncrypted()) {
|
if (walletsManager.areWalletsEncrypted()) {
|
||||||
new Popup().information(Res.get("seed.warn.notEncryptedAnymore"))
|
new Popup().information(Res.get("seed.warn.notEncryptedAnymore"))
|
||||||
|
.closeButtonText(Res.get("shared.no"))
|
||||||
|
.actionButtonText(Res.get("shared.yes"))
|
||||||
|
.onAction(this::doRestoreDateCheck)
|
||||||
|
.show();
|
||||||
|
} else {
|
||||||
|
doRestoreDateCheck();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doRestoreDateCheck() {
|
||||||
|
if (restoreDatePicker.getValue() == null) {
|
||||||
|
// Provide feedback when attempting to restore a wallet from seed words without specifying a date
|
||||||
|
new Popup().information(Res.get("seed.warn.walletDateEmpty"))
|
||||||
.closeButtonText(Res.get("shared.no"))
|
.closeButtonText(Res.get("shared.no"))
|
||||||
.actionButtonText(Res.get("shared.yes"))
|
.actionButtonText(Res.get("shared.yes"))
|
||||||
.onAction(this::doRestore)
|
.onAction(this::doRestore)
|
||||||
@ -248,7 +261,7 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doRestore() {
|
private LocalDate getWalletDate() {
|
||||||
LocalDate walletDate = restoreDatePicker.getValue();
|
LocalDate walletDate = restoreDatePicker.getValue();
|
||||||
// Even though no current Bisq wallet could have been created before the v0.5 release date (2017.06.28),
|
// Even though no current Bisq wallet could have been created before the v0.5 release date (2017.06.28),
|
||||||
// the user may want to import from a seed generated by another wallet.
|
// the user may want to import from a seed generated by another wallet.
|
||||||
@ -264,7 +277,11 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
|
|||||||
} else if (walletDate.isAfter(LocalDate.now())) {
|
} else if (walletDate.isAfter(LocalDate.now())) {
|
||||||
walletDate = LocalDate.now();
|
walletDate = LocalDate.now();
|
||||||
}
|
}
|
||||||
|
return walletDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doRestore() {
|
||||||
|
LocalDate walletDate = getWalletDate();
|
||||||
// We subtract 1 day to be sure to not have any issues with timezones. Even if we can be sure that the timezone
|
// We subtract 1 day to be sure to not have any issues with timezones. Even if we can be sure that the timezone
|
||||||
// is handled correctly it could be that the user created the wallet in one timezone and make a restore at
|
// is handled correctly it could be that the user created the wallet in one timezone and make a restore at
|
||||||
// a different timezone which could lead in the worst case that he miss the first day of the wallet transactions.
|
// a different timezone which could lead in the worst case that he miss the first day of the wallet transactions.
|
||||||
|
@ -186,8 +186,9 @@ public class BondsView extends ActivatableView<GridPane, Void> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
column.setComparator(Comparator.comparing(e -> e.getBond().getAmount()));
|
||||||
tableView.getColumns().add(column);
|
tableView.getColumns().add(column);
|
||||||
|
|
||||||
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.lockTime"));
|
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.lockTime"));
|
||||||
column.setMinWidth(40);
|
column.setMinWidth(40);
|
||||||
column.setComparator(Comparator.comparingInt(v -> v.getBond().getLockTime()));
|
column.setComparator(Comparator.comparingInt(v -> v.getBond().getLockTime()));
|
||||||
@ -207,6 +208,7 @@ public class BondsView extends ActivatableView<GridPane, Void> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
column.setComparator(Comparator.comparing(e -> e.getBond().getLockTime()));
|
||||||
tableView.getColumns().add(column);
|
tableView.getColumns().add(column);
|
||||||
|
|
||||||
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.bondState"));
|
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.bondState"));
|
||||||
@ -230,6 +232,7 @@ public class BondsView extends ActivatableView<GridPane, Void> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
column.setComparator(Comparator.comparing(BondListItem::getBondStateString));
|
||||||
tableView.getColumns().add(column);
|
tableView.getColumns().add(column);
|
||||||
|
|
||||||
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.bondType"));
|
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.bondType"));
|
||||||
@ -251,6 +254,7 @@ public class BondsView extends ActivatableView<GridPane, Void> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
column.setComparator(Comparator.comparing(BondListItem::getBondType));
|
||||||
tableView.getColumns().add(column);
|
tableView.getColumns().add(column);
|
||||||
|
|
||||||
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.details"));
|
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.details"));
|
||||||
@ -285,6 +289,7 @@ public class BondsView extends ActivatableView<GridPane, Void> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
column.setComparator(Comparator.comparing(BondListItem::getBondDetails));
|
||||||
tableView.getColumns().add(column);
|
tableView.getColumns().add(column);
|
||||||
|
|
||||||
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.lockupDate"));
|
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.lockupDate"));
|
||||||
@ -306,6 +311,7 @@ public class BondsView extends ActivatableView<GridPane, Void> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
column.setComparator(Comparator.comparing(e -> e.getBond().getLockupDate()));
|
||||||
tableView.getColumns().add(column);
|
tableView.getColumns().add(column);
|
||||||
|
|
||||||
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.lockupTxId"));
|
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.lockupTxId"));
|
||||||
@ -340,6 +346,7 @@ public class BondsView extends ActivatableView<GridPane, Void> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
column.setComparator(Comparator.comparing(BondListItem::getLockupTxId));
|
||||||
tableView.getColumns().add(column);
|
tableView.getColumns().add(column);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,8 +190,8 @@ public class ProofOfBurnView extends ActivatableView<GridPane, Void> implements
|
|||||||
preImageTextField.setValidator(new InputValidator());
|
preImageTextField.setValidator(new InputValidator());
|
||||||
|
|
||||||
updateList();
|
updateList();
|
||||||
GUIUtil.setFitToRowsForTableView(myItemsTableView, 41, 28, 2, 4);
|
GUIUtil.setFitToRowsForTableView(myItemsTableView, 41, 28, 4, 6);
|
||||||
GUIUtil.setFitToRowsForTableView(allTxsTableView, 41, 28, 2, 100);
|
GUIUtil.setFitToRowsForTableView(allTxsTableView, 41, 28, 2, 10);
|
||||||
updateButtonState();
|
updateButtonState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,13 +265,12 @@ public class ProofOfBurnView extends ActivatableView<GridPane, Void> implements
|
|||||||
.map(myProofOfBurn -> new MyProofOfBurnListItem(myProofOfBurn, proofOfBurnService, bsqFormatter))
|
.map(myProofOfBurn -> new MyProofOfBurnListItem(myProofOfBurn, proofOfBurnService, bsqFormatter))
|
||||||
.sorted(Comparator.comparing(MyProofOfBurnListItem::getDate).reversed())
|
.sorted(Comparator.comparing(MyProofOfBurnListItem::getDate).reversed())
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
GUIUtil.setFitToRowsForTableView(myItemsTableView, 41, 28, 2, 4);
|
GUIUtil.setFitToRowsForTableView(myItemsTableView, 41, 28, 4, 6);
|
||||||
|
|
||||||
|
|
||||||
allItemsObservableList.setAll(proofOfBurnService.getProofOfBurnTxList().stream()
|
allItemsObservableList.setAll(proofOfBurnService.getProofOfBurnTxList().stream()
|
||||||
.map(tx -> new ProofOfBurnListItem(tx, proofOfBurnService, bsqFormatter))
|
.map(tx -> new ProofOfBurnListItem(tx, proofOfBurnService, bsqFormatter))
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
GUIUtil.setFitToRowsForTableView(allTxsTableView, 41, 28, 2, 100);
|
GUIUtil.setFitToRowsForTableView(allTxsTableView, 41, 28, 2, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateButtonState() {
|
private void updateButtonState() {
|
||||||
|
@ -286,6 +286,11 @@ public class ProposalsView extends ActivatableView<GridPane, Void> implements Bs
|
|||||||
availableForVoting = Coin.valueOf(0);
|
availableForVoting = Coin.valueOf(0);
|
||||||
stakeInputTextField.setPromptText(Res.get("dao.proposal.myVote.stake.prompt",
|
stakeInputTextField.setPromptText(Res.get("dao.proposal.myVote.stake.prompt",
|
||||||
bsqFormatter.formatCoinWithCode(availableForVoting)));
|
bsqFormatter.formatCoinWithCode(availableForVoting)));
|
||||||
|
|
||||||
|
BsqValidator stakeInputTextFieldValidator = new BsqValidator(bsqFormatter);
|
||||||
|
stakeInputTextFieldValidator.setMaxValue(availableForVoting);
|
||||||
|
|
||||||
|
stakeInputTextField.setValidator(stakeInputTextFieldValidator);
|
||||||
} else
|
} else
|
||||||
stakeInputTextField.setPromptText("");
|
stakeInputTextField.setPromptText("");
|
||||||
}
|
}
|
||||||
|
@ -226,7 +226,7 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
|
|||||||
final double doubleValue = (double) object;
|
final double doubleValue = (double) object;
|
||||||
if (CurrencyUtil.isCryptoCurrency(model.getCurrencyCode())) {
|
if (CurrencyUtil.isCryptoCurrency(model.getCurrencyCode())) {
|
||||||
final String withCryptoPrecision = FormattingUtils.formatRoundedDoubleWithPrecision(doubleValue, cryptoPrecision);
|
final String withCryptoPrecision = FormattingUtils.formatRoundedDoubleWithPrecision(doubleValue, cryptoPrecision);
|
||||||
if (withCryptoPrecision.equals("0.000")) {
|
if (withCryptoPrecision.substring(0,3).equals("0.0")) {
|
||||||
cryptoPrecision = 8;
|
cryptoPrecision = 8;
|
||||||
return FormattingUtils.formatRoundedDoubleWithPrecision(doubleValue, cryptoPrecision);
|
return FormattingUtils.formatRoundedDoubleWithPrecision(doubleValue, cryptoPrecision);
|
||||||
} else {
|
} else {
|
||||||
|
@ -282,6 +282,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel implements Bs
|
|||||||
amount.get(),
|
amount.get(),
|
||||||
minAmount.get(),
|
minAmount.get(),
|
||||||
price.get(),
|
price.get(),
|
||||||
|
txFeeFromFeeService,
|
||||||
useMarketBasedPrice.get(),
|
useMarketBasedPrice.get(),
|
||||||
marketPriceMargin,
|
marketPriceMargin,
|
||||||
buyerSecurityDeposit.get(),
|
buyerSecurityDeposit.get(),
|
||||||
|
@ -812,14 +812,16 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
|
|||||||
// We want to trigger a recalculation of the volume and minAmount
|
// We want to trigger a recalculation of the volume and minAmount
|
||||||
UserThread.execute(() -> {
|
UserThread.execute(() -> {
|
||||||
onFocusOutVolumeTextField(true, false);
|
onFocusOutVolumeTextField(true, false);
|
||||||
// do not update BTC Amount or minAmount here
|
triggerFocusOutOnAmountFields();
|
||||||
// issue 2798: "after a few edits of offer the BTC amount has increased"
|
|
||||||
// intentionally removed: onFocusOutAmountTextField(true, false);
|
|
||||||
// intentionally removed: onFocusOutMinAmountTextField(true, false);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void triggerFocusOutOnAmountFields() {
|
||||||
|
onFocusOutAmountTextField(true, false);
|
||||||
|
onFocusOutMinAmountTextField(true, false);
|
||||||
|
}
|
||||||
|
|
||||||
public void onFocusOutPriceAsPercentageTextField(boolean oldValue, boolean newValue) {
|
public void onFocusOutPriceAsPercentageTextField(boolean oldValue, boolean newValue) {
|
||||||
inputIsMarketBasedPrice = !oldValue && newValue;
|
inputIsMarketBasedPrice = !oldValue && newValue;
|
||||||
if (oldValue && !newValue) {
|
if (oldValue && !newValue) {
|
||||||
|
@ -130,6 +130,7 @@ public class FilterWindow extends Overlay<FilterWindow> {
|
|||||||
InputTextField arbitratorsInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.arbitrators"));
|
InputTextField arbitratorsInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.arbitrators"));
|
||||||
InputTextField mediatorsInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.mediators"));
|
InputTextField mediatorsInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.mediators"));
|
||||||
InputTextField refundAgentsInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.refundAgents"));
|
InputTextField refundAgentsInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.refundAgents"));
|
||||||
|
InputTextField btcFeeReceiverAddressesInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.btcFeeReceiverAddresses"));
|
||||||
InputTextField seedNodesInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.seedNode"));
|
InputTextField seedNodesInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.seedNode"));
|
||||||
InputTextField priceRelayNodesInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.priceRelayNode"));
|
InputTextField priceRelayNodesInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.priceRelayNode"));
|
||||||
InputTextField btcNodesInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.btcNode"));
|
InputTextField btcNodesInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("filterWindow.btcNode"));
|
||||||
@ -149,6 +150,7 @@ public class FilterWindow extends Overlay<FilterWindow> {
|
|||||||
setupFieldFromList(arbitratorsInputTextField, filter.getArbitrators());
|
setupFieldFromList(arbitratorsInputTextField, filter.getArbitrators());
|
||||||
setupFieldFromList(mediatorsInputTextField, filter.getMediators());
|
setupFieldFromList(mediatorsInputTextField, filter.getMediators());
|
||||||
setupFieldFromList(refundAgentsInputTextField, filter.getRefundAgents());
|
setupFieldFromList(refundAgentsInputTextField, filter.getRefundAgents());
|
||||||
|
setupFieldFromList(btcFeeReceiverAddressesInputTextField, filter.getBtcFeeReceiverAddresses());
|
||||||
setupFieldFromList(seedNodesInputTextField, filter.getSeedNodes());
|
setupFieldFromList(seedNodesInputTextField, filter.getSeedNodes());
|
||||||
setupFieldFromList(priceRelayNodesInputTextField, filter.getPriceRelayNodes());
|
setupFieldFromList(priceRelayNodesInputTextField, filter.getPriceRelayNodes());
|
||||||
setupFieldFromList(btcNodesInputTextField, filter.getBtcNodes());
|
setupFieldFromList(btcNodesInputTextField, filter.getBtcNodes());
|
||||||
@ -177,7 +179,8 @@ public class FilterWindow extends Overlay<FilterWindow> {
|
|||||||
disableTradeBelowVersionInputTextField.getText(),
|
disableTradeBelowVersionInputTextField.getText(),
|
||||||
readAsList(mediatorsInputTextField),
|
readAsList(mediatorsInputTextField),
|
||||||
readAsList(refundAgentsInputTextField),
|
readAsList(refundAgentsInputTextField),
|
||||||
readAsList(bannedSignerPubKeysInputTextField)
|
readAsList(bannedSignerPubKeysInputTextField),
|
||||||
|
readAsList(btcFeeReceiverAddressesInputTextField)
|
||||||
),
|
),
|
||||||
keyInputTextField.getText())
|
keyInputTextField.getText())
|
||||||
)
|
)
|
||||||
|
@ -30,8 +30,8 @@ import bisq.core.account.witness.AccountAgeWitnessService;
|
|||||||
import bisq.core.offer.OpenOffer;
|
import bisq.core.offer.OpenOffer;
|
||||||
import bisq.core.provider.price.PriceFeedService;
|
import bisq.core.provider.price.PriceFeedService;
|
||||||
import bisq.core.user.Preferences;
|
import bisq.core.user.Preferences;
|
||||||
import bisq.core.util.coin.BsqFormatter;
|
|
||||||
import bisq.core.util.FormattingUtils;
|
import bisq.core.util.FormattingUtils;
|
||||||
|
import bisq.core.util.coin.BsqFormatter;
|
||||||
import bisq.core.util.coin.CoinFormatter;
|
import bisq.core.util.coin.CoinFormatter;
|
||||||
|
|
||||||
import bisq.common.handlers.ErrorMessageHandler;
|
import bisq.common.handlers.ErrorMessageHandler;
|
||||||
@ -108,4 +108,10 @@ class EditOfferViewModel extends MutableOfferViewModel<EditOfferDataModel> {
|
|||||||
public boolean isSecurityDepositValid() {
|
public boolean isSecurityDepositValid() {
|
||||||
return securityDepositValidator.validate(buyerSecurityDeposit.get()).isValid;
|
return securityDepositValidator.validate(buyerSecurityDeposit.get()).isValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void triggerFocusOutOnAmountFields() {
|
||||||
|
// do not update BTC Amount or minAmount here
|
||||||
|
// issue 2798: "after a few edits of offer the BTC amount has increased"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,14 +31,15 @@
|
|||||||
<columns>
|
<columns>
|
||||||
<TableColumn fx:id="offerIdColumn" minWidth="110" maxWidth="130"/>
|
<TableColumn fx:id="offerIdColumn" minWidth="110" maxWidth="130"/>
|
||||||
<TableColumn fx:id="dateColumn" minWidth="180"/>
|
<TableColumn fx:id="dateColumn" minWidth="180"/>
|
||||||
<TableColumn fx:id="marketColumn" minWidth="90"/>
|
<TableColumn fx:id="marketColumn" minWidth="75"/>
|
||||||
<TableColumn fx:id="priceColumn" minWidth="150"/>
|
<TableColumn fx:id="priceColumn" minWidth="110"/>
|
||||||
<TableColumn fx:id="amountColumn" minWidth="150"/>
|
<TableColumn fx:id="amountColumn" minWidth="100"/>
|
||||||
<TableColumn fx:id="volumeColumn" minWidth="170"/>
|
<TableColumn fx:id="volumeColumn" minWidth="150"/>
|
||||||
|
<TableColumn fx:id="paymentMethodColumn" minWidth="120" maxWidth="170"/>
|
||||||
<TableColumn fx:id="directionColumn" minWidth="80"/>
|
<TableColumn fx:id="directionColumn" minWidth="80"/>
|
||||||
<TableColumn fx:id="deactivateItemColumn" minWidth="100" maxWidth="100" sortable="false"/>
|
<TableColumn fx:id="deactivateItemColumn" minWidth="60" maxWidth="60" sortable="false"/>
|
||||||
<TableColumn fx:id="editItemColumn" minWidth="60" maxWidth="60" sortable="false"/>
|
<TableColumn fx:id="editItemColumn" minWidth="50" maxWidth="60" sortable="false"/>
|
||||||
<TableColumn fx:id="removeItemColumn" minWidth="60" maxWidth="60" sortable="false"/>
|
<TableColumn fx:id="removeItemColumn" minWidth="50" maxWidth="60" sortable="false"/>
|
||||||
</columns>
|
</columns>
|
||||||
</TableView>
|
</TableView>
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||||||
@FXML
|
@FXML
|
||||||
TableColumn<OpenOfferListItem, OpenOfferListItem> priceColumn, amountColumn, volumeColumn,
|
TableColumn<OpenOfferListItem, OpenOfferListItem> priceColumn, amountColumn, volumeColumn,
|
||||||
marketColumn, directionColumn, dateColumn, offerIdColumn, deactivateItemColumn,
|
marketColumn, directionColumn, dateColumn, offerIdColumn, deactivateItemColumn,
|
||||||
removeItemColumn, editItemColumn;
|
removeItemColumn, editItemColumn, paymentMethodColumn;
|
||||||
private final Navigation navigation;
|
private final Navigation navigation;
|
||||||
private final OfferDetailsWindow offerDetailsWindow;
|
private final OfferDetailsWindow offerDetailsWindow;
|
||||||
private SortedList<OpenOfferListItem> sortedList;
|
private SortedList<OpenOfferListItem> sortedList;
|
||||||
@ -84,6 +84,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
|
paymentMethodColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.paymentMethod")));
|
||||||
priceColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.price")));
|
priceColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.price")));
|
||||||
amountColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.BTCMinMax")));
|
amountColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.BTCMinMax")));
|
||||||
volumeColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.amountMinMax")));
|
volumeColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.amountMinMax")));
|
||||||
@ -101,6 +102,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||||||
setPriceColumnCellFactory();
|
setPriceColumnCellFactory();
|
||||||
setAmountColumnCellFactory();
|
setAmountColumnCellFactory();
|
||||||
setVolumeColumnCellFactory();
|
setVolumeColumnCellFactory();
|
||||||
|
setPaymentMethodColumnCellFactory();
|
||||||
setDateColumnCellFactory();
|
setDateColumnCellFactory();
|
||||||
setDeactivateColumnCellFactory();
|
setDeactivateColumnCellFactory();
|
||||||
setEditColumnCellFactory();
|
setEditColumnCellFactory();
|
||||||
@ -116,6 +118,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||||||
priceColumn.setComparator(Comparator.comparing(o -> o.getOffer().getPrice(), Comparator.nullsFirst(Comparator.naturalOrder())));
|
priceColumn.setComparator(Comparator.comparing(o -> o.getOffer().getPrice(), Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||||
volumeColumn.setComparator(Comparator.comparing(o -> o.getOffer().getVolume(), Comparator.nullsFirst(Comparator.naturalOrder())));
|
volumeColumn.setComparator(Comparator.comparing(o -> o.getOffer().getVolume(), Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||||
dateColumn.setComparator(Comparator.comparing(o -> o.getOffer().getDate()));
|
dateColumn.setComparator(Comparator.comparing(o -> o.getOffer().getDate()));
|
||||||
|
paymentMethodColumn.setComparator(Comparator.comparing(o -> o.getOffer().getPaymentMethod().getId()));
|
||||||
|
|
||||||
dateColumn.setSortType(TableColumn.SortType.DESCENDING);
|
dateColumn.setSortType(TableColumn.SortType.DESCENDING);
|
||||||
tableView.getSortOrder().add(dateColumn);
|
tableView.getSortOrder().add(dateColumn);
|
||||||
@ -330,6 +333,31 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setPaymentMethodColumnCellFactory() {
|
||||||
|
paymentMethodColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||||
|
paymentMethodColumn.setCellFactory(
|
||||||
|
new Callback<>() {
|
||||||
|
@Override
|
||||||
|
public TableCell<OpenOfferListItem, OpenOfferListItem> call(
|
||||||
|
TableColumn<OpenOfferListItem, OpenOfferListItem> column) {
|
||||||
|
return new TableCell<>() {
|
||||||
|
@Override
|
||||||
|
public void updateItem(final OpenOfferListItem item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
getStyleClass().removeAll("offer-disabled");
|
||||||
|
|
||||||
|
if (item != null) {
|
||||||
|
if (model.isDeactivated(item)) getStyleClass().add("offer-disabled");
|
||||||
|
setGraphic(new AutoTooltipLabel(model.getPaymentMethod(item)));
|
||||||
|
} else {
|
||||||
|
setGraphic(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void setDirectionColumnCellFactory() {
|
private void setDirectionColumnCellFactory() {
|
||||||
directionColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
directionColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
|
||||||
directionColumn.setCellFactory(
|
directionColumn.setCellFactory(
|
||||||
|
@ -42,6 +42,8 @@ import javax.inject.Named;
|
|||||||
|
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
class OpenOffersViewModel extends ActivatableWithDataModel<OpenOffersDataModel> implements ViewModel {
|
class OpenOffersViewModel extends ActivatableWithDataModel<OpenOffersDataModel> implements ViewModel {
|
||||||
private final P2PService p2PService;
|
private final P2PService p2PService;
|
||||||
private final CoinFormatter btcFormatter;
|
private final CoinFormatter btcFormatter;
|
||||||
@ -118,6 +120,17 @@ class OpenOffersViewModel extends ActivatableWithDataModel<OpenOffersDataModel>
|
|||||||
return CurrencyUtil.getCurrencyPair(item.getOffer().getCurrencyCode());
|
return CurrencyUtil.getCurrencyPair(item.getOffer().getCurrencyCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getPaymentMethod(OpenOfferListItem item) {
|
||||||
|
String result = "";
|
||||||
|
if (item != null) {
|
||||||
|
Offer offer = item.getOffer();
|
||||||
|
checkNotNull(offer);
|
||||||
|
checkNotNull(offer.getPaymentMethod());
|
||||||
|
result = offer.getPaymentMethodNameWithCountryCode();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
String getDate(OpenOfferListItem item) {
|
String getDate(OpenOfferListItem item) {
|
||||||
return DisplayUtils.formatDateTime(item.getOffer().getDate());
|
return DisplayUtils.formatDateTime(item.getOffer().getDate());
|
||||||
}
|
}
|
||||||
|
@ -442,8 +442,26 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||||||
// Delay display to next render frame to avoid that the popup is first quickly displayed in default position
|
// Delay display to next render frame to avoid that the popup is first quickly displayed in default position
|
||||||
// and after a short moment in the correct position
|
// and after a short moment in the correct position
|
||||||
UserThread.execute(() -> chatPopupStage.setOpacity(1));
|
UserThread.execute(() -> chatPopupStage.setOpacity(1));
|
||||||
|
updateChatMessageCount(trade, badgeByTrade.get(trade.getId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateChatMessageCount(Trade trade, JFXBadge badge) {
|
||||||
|
if (!trade.getId().equals(tradeIdOfOpenChat)) {
|
||||||
|
updateNewChatMessagesByTradeMap();
|
||||||
|
long num = newChatMessagesByTradeMap.get(trade.getId());
|
||||||
|
if (num > 0) {
|
||||||
|
badge.setText(String.valueOf(num));
|
||||||
|
badge.setEnabled(true);
|
||||||
|
} else {
|
||||||
|
badge.setText("");
|
||||||
|
badge.setEnabled(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
badge.setText("");
|
||||||
|
badge.setEnabled(false);
|
||||||
|
}
|
||||||
|
badge.refreshBadge();
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Private
|
// Private
|
||||||
@ -729,17 +747,17 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||||||
}
|
}
|
||||||
|
|
||||||
button.setOnAction(e -> {
|
button.setOnAction(e -> {
|
||||||
|
tableView.getSelectionModel().select(this.getIndex());
|
||||||
openChat(trade);
|
openChat(trade);
|
||||||
update(trade, badge);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!listenerByTrade.containsKey(id)) {
|
if (!listenerByTrade.containsKey(id)) {
|
||||||
ListChangeListener<ChatMessage> listener = c -> update(trade, badge);
|
ListChangeListener<ChatMessage> listener = c -> updateChatMessageCount(trade, badge);
|
||||||
listenerByTrade.put(id, listener);
|
listenerByTrade.put(id, listener);
|
||||||
trade.getChatMessages().addListener(listener);
|
trade.getChatMessages().addListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
update(trade, badge);
|
updateChatMessageCount(trade, badge);
|
||||||
|
|
||||||
setGraphic(badge);
|
setGraphic(badge);
|
||||||
} else {
|
} else {
|
||||||
@ -747,23 +765,6 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void update(Trade trade, JFXBadge badge) {
|
|
||||||
if (!trade.getId().equals(tradeIdOfOpenChat)) {
|
|
||||||
updateNewChatMessagesByTradeMap();
|
|
||||||
long num = newChatMessagesByTradeMap.get(trade.getId());
|
|
||||||
if (num > 0) {
|
|
||||||
badge.setText(String.valueOf(num));
|
|
||||||
badge.setEnabled(true);
|
|
||||||
} else {
|
|
||||||
badge.setText("");
|
|
||||||
badge.setEnabled(false);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
badge.setText("");
|
|
||||||
badge.setEnabled(false);
|
|
||||||
}
|
|
||||||
badge.refreshBadge();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -276,13 +276,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
|||||||
Offer offer = item.getTrade().getOffer();
|
Offer offer = item.getTrade().getOffer();
|
||||||
checkNotNull(offer);
|
checkNotNull(offer);
|
||||||
checkNotNull(offer.getPaymentMethod());
|
checkNotNull(offer.getPaymentMethod());
|
||||||
String method = Res.get(offer.getPaymentMethod().getId() + "_SHORT");
|
result = offer.getPaymentMethodNameWithCountryCode();
|
||||||
String methodCountryCode = offer.getCountryCode();
|
|
||||||
|
|
||||||
if (methodCountryCode != null)
|
|
||||||
result = method + " (" + methodCountryCode + ")";
|
|
||||||
else
|
|
||||||
result = method;
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -135,55 +135,6 @@
|
|||||||
-bs-chart-dao-line2: -bs-color-blue-2;
|
-bs-chart-dao-line2: -bs-color-blue-2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* list view */
|
|
||||||
.list-view .list-cell {
|
|
||||||
-fx-background-color: -bs-background-color;
|
|
||||||
}
|
|
||||||
.list-view .list-cell:odd {
|
|
||||||
-fx-background-color: derive(-bs-background-color, -5%);
|
|
||||||
}
|
|
||||||
.list-view .list-cell:even {
|
|
||||||
-fx-background-color: derive(-bs-background-color, 5%);
|
|
||||||
}
|
|
||||||
.list-view .list-cell:selected,
|
|
||||||
.table-view .table-cell:selected {
|
|
||||||
-fx-background: -fx-accent;
|
|
||||||
-fx-background-color: -fx-selection-bar;
|
|
||||||
-fx-border-color: -fx-selection-bar;
|
|
||||||
}
|
|
||||||
|
|
||||||
.number-column.table-cell {
|
|
||||||
-fx-background-color: -bs-background-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* table view */
|
|
||||||
.table-view, .table-cell:focused, .table-row-cell {
|
|
||||||
-fx-background: transparent;
|
|
||||||
}
|
|
||||||
.table-view .table-row-cell:even .table-cell {
|
|
||||||
-fx-background-color: derive(-bs-background-color, 5%);
|
|
||||||
-fx-border-color: derive(-bs-background-color,5%);
|
|
||||||
}
|
|
||||||
.table-view .table-row-cell:odd .table-cell {
|
|
||||||
-fx-background-color: derive(-bs-background-color,-5%);
|
|
||||||
-fx-border-color: derive(-bs-background-color,-5%);
|
|
||||||
}
|
|
||||||
.table-view .table-row-cell:selected .table-cell {
|
|
||||||
-fx-background: -fx-accent;
|
|
||||||
-fx-background-color: -fx-selection-bar;
|
|
||||||
-fx-border-color: -fx-selection-bar;
|
|
||||||
}
|
|
||||||
.table-row-cell {
|
|
||||||
-fx-border-color: -bs-background-color;
|
|
||||||
}
|
|
||||||
.table-row-cell:empty, .table-row-cell:empty:even, .table-row-cell:empty:odd {
|
|
||||||
-fx-background-color: -bs-background-color;
|
|
||||||
-fx-min-height: 36;
|
|
||||||
}
|
|
||||||
.offer-table .table-row-cell {
|
|
||||||
-fx-background: -fx-accent;
|
|
||||||
-fx-background-color: -bs-color-gray-6;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* tab pane */
|
/* tab pane */
|
||||||
.jfx-tab-pane .tab-content-area {
|
.jfx-tab-pane .tab-content-area {
|
||||||
|
@ -1129,6 +1129,7 @@ public class GUIUtil {
|
|||||||
RegexValidator regexValidator = new RegexValidator();
|
RegexValidator regexValidator = new RegexValidator();
|
||||||
String portRegexPattern = "(0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])";
|
String portRegexPattern = "(0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])";
|
||||||
String onionV2RegexPattern = String.format("[a-zA-Z2-7]{16}\\.onion(?:\\:%1$s)?", portRegexPattern);
|
String onionV2RegexPattern = String.format("[a-zA-Z2-7]{16}\\.onion(?:\\:%1$s)?", portRegexPattern);
|
||||||
|
String onionV3RegexPattern = String.format("[a-zA-Z2-7]{56}\\.onion(?:\\:%1$s)?", portRegexPattern);
|
||||||
String ipv4RegexPattern = String.format("(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}" +
|
String ipv4RegexPattern = String.format("(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}" +
|
||||||
"(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" +
|
"(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" +
|
||||||
"(?:\\:%1$s)?", portRegexPattern);
|
"(?:\\:%1$s)?", portRegexPattern);
|
||||||
@ -1152,8 +1153,8 @@ public class GUIUtil {
|
|||||||
")"; // (IPv4-Embedded IPv6 Address)
|
")"; // (IPv4-Embedded IPv6 Address)
|
||||||
ipv6RegexPattern = String.format("(?:%1$s)|(?:\\[%1$s\\]\\:%2$s)", ipv6RegexPattern, portRegexPattern);
|
ipv6RegexPattern = String.format("(?:%1$s)|(?:\\[%1$s\\]\\:%2$s)", ipv6RegexPattern, portRegexPattern);
|
||||||
String fqdnRegexPattern = String.format("(((?!-)[a-zA-Z0-9-]{1,63}(?<!-)\\.)+(?!onion)[a-zA-Z]{2,63}(?:\\:%1$s)?)", portRegexPattern);
|
String fqdnRegexPattern = String.format("(((?!-)[a-zA-Z0-9-]{1,63}(?<!-)\\.)+(?!onion)[a-zA-Z]{2,63}(?:\\:%1$s)?)", portRegexPattern);
|
||||||
regexValidator.setPattern(String.format("^(?:(?:(?:%1$s)|(?:%2$s)|(?:%3$s)|(?:%4$s)),\\s*)*(?:(?:%1$s)|(?:%2$s)|(?:%3$s)|(?:%4$s))*$",
|
regexValidator.setPattern(String.format("^(?:(?:(?:%1$s)|(?:%2$s)|(?:%3$s)|(?:%4$s)|(?:%5$s)),\\s*)*(?:(?:%1$s)|(?:%2$s)|(?:%3$s)|(?:%4$s)|(?:%5$s))*$",
|
||||||
onionV2RegexPattern, ipv4RegexPattern, ipv6RegexPattern, fqdnRegexPattern));
|
onionV2RegexPattern, onionV3RegexPattern, ipv4RegexPattern, ipv6RegexPattern, fqdnRegexPattern));
|
||||||
return regexValidator;
|
return regexValidator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,7 +141,8 @@ public class GUIUtilTest {
|
|||||||
assertFalse(regexValidator.validate("abcdefghijklmnop.onion:").isValid);
|
assertFalse(regexValidator.validate("abcdefghijklmnop.onion:").isValid);
|
||||||
|
|
||||||
// onion v3 addresses
|
// onion v3 addresses
|
||||||
assertFalse(regexValidator.validate("32zzibxmqi2ybxpqyggwwuwz7a3lbvtzoloti7cxoevyvijexvgsfeid.onion:8333").isValid);
|
assertFalse(regexValidator.validate("32zzibxmqi2ybxpqyggwwuwz7a3lbvtzoloti7cxoevyvijexvgsfei.onion:8333").isValid); // 1 missing char
|
||||||
|
assertTrue(regexValidator.validate("wizseedscybbttk4bmb2lzvbuk2jtect37lcpva4l3twktmkzemwbead.onion:8000").isValid);
|
||||||
|
|
||||||
// ipv4 addresses
|
// ipv4 addresses
|
||||||
assertTrue(regexValidator.validate("12.34.56.78").isValid);
|
assertTrue(regexValidator.validate("12.34.56.78").isValid);
|
||||||
|
@ -22,7 +22,7 @@ You do _not_ need to install Gradle to complete the following command. The `grad
|
|||||||
./gradlew build
|
./gradlew build
|
||||||
|
|
||||||
If on Windows run `gradlew.bat build` instead.
|
If on Windows run `gradlew.bat build` instead.
|
||||||
|
If in need to install JAVA check out - https://github.com/bisq-network/bisq/tree/master/scripts
|
||||||
|
|
||||||
## Run
|
## Run
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ Note: bisq runs fine on jdk10 and jdk11. jdk12 is currently not supported.
|
|||||||
./bisq-desktop
|
./bisq-desktop
|
||||||
|
|
||||||
If on Windows use the `bisq-desktop.bat` script instead.
|
If on Windows use the `bisq-desktop.bat` script instead.
|
||||||
|
If in need to install JAVA checkout the install_java scripts at https://github.com/bisq-network/bisq/tree/master/scripts
|
||||||
|
|
||||||
## See also
|
## See also
|
||||||
|
|
||||||
|
BIN
p2p/src/main/resources/AccountAgeWitnessStore_BTC_MAINNET
(Stored with Git LFS)
BIN
p2p/src/main/resources/AccountAgeWitnessStore_BTC_MAINNET
(Stored with Git LFS)
Binary file not shown.
BIN
p2p/src/main/resources/DaoStateStore_BTC_MAINNET
(Stored with Git LFS)
BIN
p2p/src/main/resources/DaoStateStore_BTC_MAINNET
(Stored with Git LFS)
Binary file not shown.
BIN
p2p/src/main/resources/SignedWitnessStore_BTC_MAINNET
(Stored with Git LFS)
BIN
p2p/src/main/resources/SignedWitnessStore_BTC_MAINNET
(Stored with Git LFS)
Binary file not shown.
BIN
p2p/src/main/resources/TradeStatistics2Store_BTC_MAINNET
(Stored with Git LFS)
BIN
p2p/src/main/resources/TradeStatistics2Store_BTC_MAINNET
(Stored with Git LFS)
Binary file not shown.
@ -72,7 +72,7 @@ curl http://localhost:8080/info
|
|||||||
If you run a main pricenode, you also are obliged to activate the monitoring feed by running
|
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/bisq-network/bisq/master/monitor/install_collectd_debian.sh | sudo bash
|
bash <(curl -s https://raw.githubusercontent.com/bisq-network/bisq/master/monitor/install_collectd_debian.sh)
|
||||||
```
|
```
|
||||||
Follow the instruction given by the script and report your certificate to the [@bisq-network/monitoring](https://github.com/orgs/bisq-network/teams/monitoring-operators) team or via the [Keybase](https://keybase.io/team/bisq) `#monitoring` channel!
|
Follow the instruction given by the script and report your certificate to the [@bisq-network/monitoring](https://github.com/orgs/bisq-network/teams/monitoring-operators) team or via the [Keybase](https://keybase.io/team/bisq) `#monitoring` channel!
|
||||||
|
|
||||||
@ -81,6 +81,12 @@ Furthermore, you are obliged to provide network size data to the monitor by runn
|
|||||||
curl -s https://raw.githubusercontent.com/bisq-network/bisq/master/pricenode/install_networksize_debian.sh | sudo bash
|
curl -s https://raw.githubusercontent.com/bisq-network/bisq/master/pricenode/install_networksize_debian.sh | sudo bash
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Updating
|
||||||
|
|
||||||
|
Update your bisq code in /bisq/bisq with ```git pull```
|
||||||
|
|
||||||
|
Then build an updated pricenode:
|
||||||
|
```./gradlew :pricenode:installDist -x test```
|
||||||
|
|
||||||
## How to deploy elsewhere
|
## How to deploy elsewhere
|
||||||
|
|
||||||
|
@ -34,6 +34,11 @@ 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 update -q
|
||||||
sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get upgrade -qq -y
|
sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get upgrade -qq -y
|
||||||
|
|
||||||
|
echo "[*] Installing Git LFS"
|
||||||
|
sudo -H -i -u "${ROOT_USER}" curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash
|
||||||
|
sudo -H -i -u "${ROOT_USER}" apt-get install git-lfs
|
||||||
|
sudo -H -i -u "${ROOT_USER}" git lfs install
|
||||||
|
|
||||||
echo "[*] Installing Tor"
|
echo "[*] Installing Tor"
|
||||||
sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get install -qq -y "${TOR_PKG}"
|
sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get install -qq -y "${TOR_PKG}"
|
||||||
|
|
||||||
@ -61,6 +66,9 @@ sudo -H -i -u "${ROOT_USER}" "${BISQ_HOME}/${BISQ_REPO_NAME}/scripts/install_jav
|
|||||||
echo "[*] Checking out Bisq ${BISQ_LATEST_RELEASE}"
|
echo "[*] Checking out Bisq ${BISQ_LATEST_RELEASE}"
|
||||||
sudo -H -i -u "${BISQ_USER}" sh -c "cd ${BISQ_HOME}/${BISQ_REPO_NAME} && git checkout ${BISQ_LATEST_RELEASE}"
|
sudo -H -i -u "${BISQ_USER}" sh -c "cd ${BISQ_HOME}/${BISQ_REPO_NAME} && git checkout ${BISQ_LATEST_RELEASE}"
|
||||||
|
|
||||||
|
echo "[*] Performing Git LFS pull"
|
||||||
|
sudo -H -i -u "${BISQ_USER}" sh -c "cd ${BISQ_HOME}/${BISQ_REPO_NAME} && git lfs pull"
|
||||||
|
|
||||||
echo "[*] Building Bisq from source"
|
echo "[*] Building Bisq from source"
|
||||||
sudo -H -i -u "${BISQ_USER}" sh -c "cd ${BISQ_HOME}/${BISQ_REPO_NAME} && ./gradlew :pricenode:installDist -x test < /dev/null" # redirect from /dev/null is necessary to workaround gradlew non-interactive shell hanging issue
|
sudo -H -i -u "${BISQ_USER}" sh -c "cd ${BISQ_HOME}/${BISQ_REPO_NAME} && ./gradlew :pricenode:installDist -x test < /dev/null" # redirect from /dev/null is necessary to workaround gradlew non-interactive shell hanging issue
|
||||||
|
|
||||||
|
@ -39,6 +39,88 @@ message GetVersionReply {
|
|||||||
string version = 1;
|
string version = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Offers
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
service Offers {
|
||||||
|
rpc GetOffers (GetOffersRequest) returns (GetOffersReply) {
|
||||||
|
}
|
||||||
|
rpc CreateOffer (CreateOfferRequest) returns (CreateOfferReply) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetOffersRequest {
|
||||||
|
string direction = 1;
|
||||||
|
string fiatCurrencyCode = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetOffersReply {
|
||||||
|
repeated OfferInfo offers = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CreateOfferRequest {
|
||||||
|
string currencyCode = 1; // TODO switch order w/ direction field in next PR
|
||||||
|
string direction = 2;
|
||||||
|
uint64 price = 3;
|
||||||
|
bool useMarketBasedPrice = 4;
|
||||||
|
double marketPriceMargin = 5;
|
||||||
|
uint64 amount = 6;
|
||||||
|
uint64 minAmount = 7;
|
||||||
|
double buyerSecurityDeposit = 8;
|
||||||
|
string paymentAccountId = 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CreateOfferReply {
|
||||||
|
bool result = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message OfferInfo {
|
||||||
|
string id = 1;
|
||||||
|
string direction = 2;
|
||||||
|
uint64 price = 3;
|
||||||
|
bool useMarketBasedPrice = 4;
|
||||||
|
double marketPriceMargin = 5;
|
||||||
|
uint64 amount = 6;
|
||||||
|
uint64 minAmount = 7;
|
||||||
|
uint64 volume = 8;
|
||||||
|
uint64 minVolume = 9;
|
||||||
|
uint64 buyerSecurityDeposit = 10;
|
||||||
|
string paymentAccountId = 11; // only used when creating offer
|
||||||
|
string paymentMethodId = 12;
|
||||||
|
string paymentMethodShortName = 13;
|
||||||
|
string baseCurrencyCode = 14;
|
||||||
|
string counterCurrencyCode = 15;
|
||||||
|
uint64 date = 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// PaymentAccounts
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
service PaymentAccounts {
|
||||||
|
rpc CreatePaymentAccount (CreatePaymentAccountRequest) returns (CreatePaymentAccountReply) {
|
||||||
|
}
|
||||||
|
rpc GetPaymentAccounts (GetPaymentAccountsRequest) returns (GetPaymentAccountsReply) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message CreatePaymentAccountRequest {
|
||||||
|
string accountName = 1;
|
||||||
|
string accountNumber = 2;
|
||||||
|
string fiatCurrencyCode = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CreatePaymentAccountReply {
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetPaymentAccountsRequest {
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetPaymentAccountsReply {
|
||||||
|
repeated PaymentAccount paymentAccounts = 1;
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// TradeStatistics
|
// TradeStatistics
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -56,69 +138,16 @@ message GetTradeStatisticsReply {
|
|||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Offer
|
// Wallets
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
service GetOffers {
|
service Wallets {
|
||||||
rpc GetOffers (GetOffersRequest) returns (GetOffersReply) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message GetOffersRequest {
|
|
||||||
}
|
|
||||||
|
|
||||||
message GetOffersReply {
|
|
||||||
repeated Offer offers = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// PaymentAccount
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
service GetPaymentAccounts {
|
|
||||||
rpc GetPaymentAccounts (GetPaymentAccountsRequest) returns (GetPaymentAccountsReply) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message GetPaymentAccountsRequest {
|
|
||||||
}
|
|
||||||
|
|
||||||
message GetPaymentAccountsReply {
|
|
||||||
repeated PaymentAccount paymentAccounts = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// PlaceOffer
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
service PlaceOffer {
|
|
||||||
rpc PlaceOffer (PlaceOfferRequest) returns (PlaceOfferReply) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message PlaceOfferRequest {
|
|
||||||
string currencyCode = 1;
|
|
||||||
string direction = 2;
|
|
||||||
uint64 price = 3;
|
|
||||||
bool useMarketBasedPrice = 4;
|
|
||||||
double marketPriceMargin = 5;
|
|
||||||
uint64 amount = 6;
|
|
||||||
uint64 minAmount = 7;
|
|
||||||
double buyerSecurityDeposit = 8;
|
|
||||||
string paymentAccountId = 9;
|
|
||||||
}
|
|
||||||
|
|
||||||
message PlaceOfferReply {
|
|
||||||
bool result = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Wallet
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
service Wallet {
|
|
||||||
rpc GetBalance (GetBalanceRequest) returns (GetBalanceReply) {
|
rpc GetBalance (GetBalanceRequest) returns (GetBalanceReply) {
|
||||||
}
|
}
|
||||||
|
rpc GetAddressBalance (GetAddressBalanceRequest) returns (GetAddressBalanceReply) {
|
||||||
|
}
|
||||||
|
rpc GetFundingAddresses (GetFundingAddressesRequest) returns (GetFundingAddressesReply) {
|
||||||
|
}
|
||||||
rpc SetWalletPassword (SetWalletPasswordRequest) returns (SetWalletPasswordReply) {
|
rpc SetWalletPassword (SetWalletPasswordRequest) returns (SetWalletPasswordReply) {
|
||||||
}
|
}
|
||||||
rpc RemoveWalletPassword (RemoveWalletPasswordRequest) returns (RemoveWalletPasswordReply) {
|
rpc RemoveWalletPassword (RemoveWalletPasswordRequest) returns (RemoveWalletPasswordReply) {
|
||||||
@ -136,6 +165,21 @@ message GetBalanceReply {
|
|||||||
uint64 balance = 1;
|
uint64 balance = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message GetAddressBalanceRequest {
|
||||||
|
string address = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetAddressBalanceReply {
|
||||||
|
AddressBalanceInfo addressBalanceInfo = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetFundingAddressesRequest {
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetFundingAddressesReply {
|
||||||
|
repeated AddressBalanceInfo addressBalanceInfo = 1;
|
||||||
|
}
|
||||||
|
|
||||||
message SetWalletPasswordRequest {
|
message SetWalletPasswordRequest {
|
||||||
string password = 1;
|
string password = 1;
|
||||||
string newPassword = 2;
|
string newPassword = 2;
|
||||||
@ -164,3 +208,9 @@ message UnlockWalletRequest {
|
|||||||
|
|
||||||
message UnlockWalletReply {
|
message UnlockWalletReply {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message AddressBalanceInfo {
|
||||||
|
string address = 1;
|
||||||
|
int64 balance = 2;
|
||||||
|
int64 numConfirmations = 3;
|
||||||
|
}
|
||||||
|
@ -629,6 +629,7 @@ message Filter {
|
|||||||
repeated string mediators = 17;
|
repeated string mediators = 17;
|
||||||
repeated string refundAgents = 18;
|
repeated string refundAgents = 18;
|
||||||
repeated string bannedSignerPubKeys = 19;
|
repeated string bannedSignerPubKeys = 19;
|
||||||
|
repeated string btc_fee_receiver_addresses = 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
// not used anymore from v0.6 on. But leave it for receiving TradeStatistics objects from older
|
// not used anymore from v0.6 on. But leave it for receiving TradeStatistics objects from older
|
||||||
|
@ -1 +1 @@
|
|||||||
1.3.4-SNAPSHOT
|
1.3.5-SNAPSHOT
|
||||||
|
@ -10,14 +10,15 @@ Highly recommended to use SSD! Minimum specs:
|
|||||||
|
|
||||||
## Software
|
## Software
|
||||||
|
|
||||||
The following OS are known to work well:
|
The following OS's are known to work well:
|
||||||
|
|
||||||
* Ubuntu 18
|
* Ubuntu 18.04
|
||||||
|
* Ubuntu 20.04
|
||||||
* FreeBSD 12
|
* FreeBSD 12
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
Start with a clean Ubuntu 18.04 LTS server installation, and run the script
|
Start with a clean Ubuntu server installation, and run the script
|
||||||
```bash
|
```bash
|
||||||
curl -s https://raw.githubusercontent.com/bisq-network/bisq/master/seednode/install_seednode_debian.sh | sudo bash
|
curl -s https://raw.githubusercontent.com/bisq-network/bisq/master/seednode/install_seednode_debian.sh | sudo bash
|
||||||
```
|
```
|
||||||
@ -66,7 +67,7 @@ macOS:
|
|||||||
If you run a main seednode, you also are obliged to activate the monitoring feed by running
|
If you run a main seednode, you also are obliged to activate the monitoring feed by running
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -s https://raw.githubusercontent.com/bisq-network/bisq/master/monitor/install_collectd_debian.sh | sudo bash
|
bash <(curl -s https://raw.githubusercontent.com/bisq-network/bisq/master/monitor/install_collectd_debian.sh)
|
||||||
```
|
```
|
||||||
Follow the instruction given by the script and report your certificate to the seednode group!
|
Follow the instruction given by the script and report your certificate to the seednode group!
|
||||||
|
|
||||||
@ -78,8 +79,7 @@ sudo -u bisq -s
|
|||||||
cd bisq
|
cd bisq
|
||||||
git fetch origin
|
git fetch origin
|
||||||
git checkout v1.2.5 # new tag
|
git checkout v1.2.5 # new tag
|
||||||
./gradlew clean
|
./gradlew clean build -x test
|
||||||
./gradlew build -x test
|
|
||||||
exit
|
exit
|
||||||
sudo service bisq restart
|
sudo service bisq restart
|
||||||
sudo journalctl --unit bisq --follow
|
sudo journalctl --unit bisq --follow
|
||||||
|
@ -60,6 +60,11 @@ sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get upgrade -qq
|
|||||||
echo "[*] Installing base packages"
|
echo "[*] Installing base packages"
|
||||||
sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get install -qq -y ${ROOT_PKG}
|
sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get install -qq -y ${ROOT_PKG}
|
||||||
|
|
||||||
|
echo "[*] Installing Git LFS"
|
||||||
|
sudo -H -i -u "${ROOT_USER}" curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash
|
||||||
|
sudo -H -i -u "${ROOT_USER}" apt-get install git-lfs
|
||||||
|
sudo -H -i -u "${ROOT_USER}" git lfs install
|
||||||
|
|
||||||
echo "[*] Cloning Bisq repo"
|
echo "[*] Cloning Bisq repo"
|
||||||
sudo -H -i -u "${ROOT_USER}" git config --global advice.detachedHead false
|
sudo -H -i -u "${ROOT_USER}" git config --global advice.detachedHead false
|
||||||
sudo -H -i -u "${ROOT_USER}" git clone --branch "${BISQ_REPO_TAG}" "${BISQ_REPO_URL}" "${ROOT_HOME}/${BISQ_REPO_NAME}"
|
sudo -H -i -u "${ROOT_USER}" git clone --branch "${BISQ_REPO_TAG}" "${BISQ_REPO_URL}" "${ROOT_HOME}/${BISQ_REPO_NAME}"
|
||||||
@ -145,6 +150,9 @@ sudo sed -i -e "s!__BISQ_HOME__!${BISQ_HOME}!" "${SYSTEMD_ENV_HOME}/bisq.env"
|
|||||||
echo "[*] Checking out Bisq ${BISQ_LATEST_RELEASE}"
|
echo "[*] Checking out Bisq ${BISQ_LATEST_RELEASE}"
|
||||||
sudo -H -i -u "${BISQ_USER}" sh -c "cd ${BISQ_HOME}/${BISQ_REPO_NAME} && git checkout ${BISQ_LATEST_RELEASE}"
|
sudo -H -i -u "${BISQ_USER}" sh -c "cd ${BISQ_HOME}/${BISQ_REPO_NAME} && git checkout ${BISQ_LATEST_RELEASE}"
|
||||||
|
|
||||||
|
echo "[*] Performing Git LFS pull"
|
||||||
|
sudo -H -i -u "${BISQ_USER}" sh -c "cd ${BISQ_HOME}/${BISQ_REPO_NAME} && git lfs pull"
|
||||||
|
|
||||||
echo "[*] Building Bisq from source"
|
echo "[*] Building Bisq from source"
|
||||||
sudo -H -i -u "${BISQ_USER}" sh -c "cd ${BISQ_HOME}/${BISQ_REPO_NAME} && ./gradlew build -x test < /dev/null" # redirect from /dev/null is necessary to workaround gradlew non-interactive shell hanging issue
|
sudo -H -i -u "${BISQ_USER}" sh -c "cd ${BISQ_HOME}/${BISQ_REPO_NAME} && ./gradlew build -x test < /dev/null" # redirect from /dev/null is necessary to workaround gradlew non-interactive shell hanging issue
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class SeedNodeMain extends ExecutableForAppWithP2p {
|
public class SeedNodeMain extends ExecutableForAppWithP2p {
|
||||||
private static final String VERSION = "1.3.4";
|
private static final String VERSION = "1.3.5";
|
||||||
private SeedNode seedNode;
|
private SeedNode seedNode;
|
||||||
|
|
||||||
public SeedNodeMain() {
|
public SeedNodeMain() {
|
||||||
|
Loading…
Reference in New Issue
Block a user