mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-21 14:24:06 +01:00
Merge branch 'arbitration-system-improvements' of https://github.com/ManfredKarrer/bisq into ManfredKarrer-arbitration-system-improvements
# Conflicts: # desktop/src/main/java/bisq/desktop/main/account/content/arbitratorselection/ArbitratorSelectionView.java
This commit is contained in:
commit
ce5a8b4f19
42 changed files with 398 additions and 805 deletions
|
@ -125,6 +125,7 @@ message OfferAvailabilityResponse {
|
|||
AvailabilityResult availability_result = 2;
|
||||
repeated int32 supported_capabilities = 3;
|
||||
string uid = 4;
|
||||
NodeAddress arbitrator = 5;
|
||||
}
|
||||
|
||||
message RefreshOfferMessage {
|
||||
|
@ -1056,6 +1057,7 @@ message OpenOffer {
|
|||
|
||||
Offer offer = 1;
|
||||
State state = 2;
|
||||
NodeAddress arbitrator_node_address = 3;
|
||||
}
|
||||
|
||||
message Tradable {
|
||||
|
|
|
@ -55,6 +55,7 @@ import java.util.Arrays;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -229,30 +230,14 @@ public class ArbitratorManager {
|
|||
);
|
||||
});
|
||||
|
||||
if (preferences.isAutoSelectArbitrators()) {
|
||||
arbitratorsObservableMap.values().stream()
|
||||
.filter(user::hasMatchingLanguage)
|
||||
.forEach(a -> {
|
||||
user.addAcceptedArbitrator(a);
|
||||
user.addAcceptedMediator(getMediator(a)
|
||||
);
|
||||
});
|
||||
} else {
|
||||
// if we don't have any arbitrator we set all matching
|
||||
// we use a delay as we might get our matching arbitrator a bit delayed (first we get one we did not selected
|
||||
// then we get our selected one - we don't want to activate the first in that case)
|
||||
UserThread.runAfter(() -> {
|
||||
if (user.getAcceptedArbitrators().isEmpty()) {
|
||||
arbitratorsObservableMap.values().stream()
|
||||
.filter(user::hasMatchingLanguage)
|
||||
.forEach(a -> {
|
||||
user.addAcceptedArbitrator(a);
|
||||
user.addAcceptedMediator(getMediator(a)
|
||||
);
|
||||
});
|
||||
}
|
||||
}, 100, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
// We keep the domain with storing the arbitrators in user as it might be still useful for mediators
|
||||
arbitratorsObservableMap.values().forEach(a -> {
|
||||
user.addAcceptedArbitrator(a);
|
||||
user.addAcceptedMediator(getMediator(a)
|
||||
);
|
||||
});
|
||||
|
||||
log.info("Available arbitrators: {}", arbitratorsObservableMap.keySet());
|
||||
}
|
||||
|
||||
// TODO we mirror arbitrator data for mediator as long we have not impl. it in the UI
|
||||
|
@ -381,4 +366,10 @@ public class ArbitratorManager {
|
|||
republishArbitratorTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<Arbitrator> getArbitratorByNodeAddress(NodeAddress nodeAddress) {
|
||||
return arbitratorsObservableMap.containsKey(nodeAddress) ?
|
||||
Optional.of(arbitratorsObservableMap.get(nodeAddress)) :
|
||||
Optional.empty();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,6 +91,7 @@ class DefaultSeedNodeAddresses {
|
|||
// 4. Rename the directory with your local onion address
|
||||
// 5. Edit here your found onion address (new NodeAddress("YOUR_ONION.onion:8002")
|
||||
new NodeAddress("rxdkppp3vicnbgqt.onion:8002"),
|
||||
new NodeAddress("4ie52dse64kaarxw.onion:8002"),
|
||||
|
||||
// LTC mainnet
|
||||
new NodeAddress("acyvotgewx46pebw.onion:8003"),
|
||||
|
|
|
@ -20,6 +20,8 @@ package bisq.core.offer;
|
|||
import bisq.core.trade.Tradable;
|
||||
import bisq.core.trade.TradableList;
|
||||
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
|
||||
import bisq.common.Timer;
|
||||
import bisq.common.UserThread;
|
||||
import bisq.common.proto.ProtoUtil;
|
||||
|
@ -28,11 +30,15 @@ import bisq.common.storage.Storage;
|
|||
import io.bisq.generated.protobuffer.PB;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Optional;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@EqualsAndHashCode
|
||||
@Slf4j
|
||||
public final class OpenOffer implements Tradable {
|
||||
|
@ -52,6 +58,10 @@ public final class OpenOffer implements Tradable {
|
|||
private final Offer offer;
|
||||
@Getter
|
||||
private State state;
|
||||
@Getter
|
||||
@Setter
|
||||
@Nullable
|
||||
private NodeAddress arbitratorNodeAddress;
|
||||
|
||||
transient private Storage<TradableList<OpenOffer>> storage;
|
||||
|
||||
|
@ -65,9 +75,10 @@ public final class OpenOffer implements Tradable {
|
|||
// PROTO BUFFER
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private OpenOffer(Offer offer, State state) {
|
||||
private OpenOffer(Offer offer, State state, @Nullable NodeAddress arbitratorNodeAddress) {
|
||||
this.offer = offer;
|
||||
this.state = state;
|
||||
this.arbitratorNodeAddress = arbitratorNodeAddress;
|
||||
|
||||
if (this.state == State.RESERVED)
|
||||
setState(State.AVAILABLE);
|
||||
|
@ -75,15 +86,19 @@ public final class OpenOffer implements Tradable {
|
|||
|
||||
@Override
|
||||
public PB.Tradable toProtoMessage() {
|
||||
return PB.Tradable.newBuilder().setOpenOffer(PB.OpenOffer.newBuilder()
|
||||
PB.OpenOffer.Builder builder = PB.OpenOffer.newBuilder()
|
||||
.setOffer(offer.toProtoMessage())
|
||||
.setState(PB.OpenOffer.State.valueOf(state.name())))
|
||||
.build();
|
||||
.setState(PB.OpenOffer.State.valueOf(state.name()));
|
||||
|
||||
Optional.ofNullable(arbitratorNodeAddress).ifPresent(nodeAddress -> builder.setArbitratorNodeAddress(nodeAddress.toProtoMessage()));
|
||||
|
||||
return PB.Tradable.newBuilder().setOpenOffer(builder).build();
|
||||
}
|
||||
|
||||
public static Tradable fromProto(PB.OpenOffer proto) {
|
||||
return new OpenOffer(Offer.fromProto(proto.getOffer()),
|
||||
ProtoUtil.enumFromProto(OpenOffer.State.class, proto.getState().name()));
|
||||
ProtoUtil.enumFromProto(OpenOffer.State.class, proto.getState().name()),
|
||||
proto.hasArbitratorNodeAddress() ? NodeAddress.fromProto(proto.getArbitratorNodeAddress()) : null);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -17,10 +17,12 @@
|
|||
|
||||
package bisq.core.offer;
|
||||
|
||||
import bisq.core.arbitration.ArbitratorManager;
|
||||
import bisq.core.btc.wallet.BsqWalletService;
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
import bisq.core.btc.wallet.TradeWalletService;
|
||||
import bisq.core.exceptions.TradePriceOutOfToleranceException;
|
||||
import bisq.core.offer.availability.ArbitratorSelection;
|
||||
import bisq.core.offer.messages.OfferAvailabilityRequest;
|
||||
import bisq.core.offer.messages.OfferAvailabilityResponse;
|
||||
import bisq.core.offer.placeoffer.PlaceOfferModel;
|
||||
|
@ -29,6 +31,7 @@ import bisq.core.provider.price.PriceFeedService;
|
|||
import bisq.core.trade.TradableList;
|
||||
import bisq.core.trade.closed.ClosedTradableManager;
|
||||
import bisq.core.trade.handlers.TransactionResultHandler;
|
||||
import bisq.core.trade.statistics.TradeStatisticsManager;
|
||||
import bisq.core.user.Preferences;
|
||||
import bisq.core.user.User;
|
||||
import bisq.core.util.Validator;
|
||||
|
@ -100,6 +103,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
private final ClosedTradableManager closedTradableManager;
|
||||
private final PriceFeedService priceFeedService;
|
||||
private final Preferences preferences;
|
||||
private final TradeStatisticsManager tradeStatisticsManager;
|
||||
private final ArbitratorManager arbitratorManager;
|
||||
private final Storage<TradableList<OpenOffer>> openOfferTradableListStorage;
|
||||
private final Map<String, OpenOffer> offersToBeEdited = new HashMap<>();
|
||||
private boolean stopped;
|
||||
|
@ -124,6 +129,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
PriceFeedService priceFeedService,
|
||||
Preferences preferences,
|
||||
PersistenceProtoResolver persistenceProtoResolver,
|
||||
TradeStatisticsManager tradeStatisticsManager,
|
||||
ArbitratorManager arbitratorManager,
|
||||
@Named(Storage.STORAGE_DIR) File storageDir) {
|
||||
this.keyRing = keyRing;
|
||||
this.user = user;
|
||||
|
@ -135,6 +142,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
this.closedTradableManager = closedTradableManager;
|
||||
this.priceFeedService = priceFeedService;
|
||||
this.preferences = preferences;
|
||||
this.tradeStatisticsManager = tradeStatisticsManager;
|
||||
this.arbitratorManager = arbitratorManager;
|
||||
|
||||
openOfferTradableListStorage = new Storage<>(storageDir, persistenceProtoResolver);
|
||||
|
||||
|
@ -324,6 +333,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
tradeWalletService,
|
||||
bsqWalletService,
|
||||
offerBookService,
|
||||
arbitratorManager,
|
||||
tradeStatisticsManager,
|
||||
user);
|
||||
PlaceOfferProtocol placeOfferProtocol = new PlaceOfferProtocol(
|
||||
model,
|
||||
|
@ -548,12 +559,17 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
try {
|
||||
Optional<OpenOffer> openOfferOptional = getOpenOfferById(request.offerId);
|
||||
AvailabilityResult availabilityResult;
|
||||
NodeAddress arbitratorNodeAddress = null;
|
||||
if (openOfferOptional.isPresent()) {
|
||||
if (openOfferOptional.get().getState() == OpenOffer.State.AVAILABLE) {
|
||||
final Offer offer = openOfferOptional.get().getOffer();
|
||||
if (preferences.getIgnoreTradersList().stream().noneMatch(hostName -> hostName.equals(peer.getHostNameWithoutPostFix()))) {
|
||||
OpenOffer openOffer = openOfferOptional.get();
|
||||
if (openOffer.getState() == OpenOffer.State.AVAILABLE) {
|
||||
final Offer offer = openOffer.getOffer();
|
||||
if (preferences.getIgnoreTradersList().stream().noneMatch(hostName -> hostName.equals(peer.getHostName()))) {
|
||||
availabilityResult = AvailabilityResult.AVAILABLE;
|
||||
|
||||
arbitratorNodeAddress = ArbitratorSelection.getLeastUsedArbitrator(tradeStatisticsManager, arbitratorManager).getNodeAddress();
|
||||
openOffer.setArbitratorNodeAddress(arbitratorNodeAddress);
|
||||
|
||||
List<NodeAddress> acceptedArbitrators = user.getAcceptedArbitratorAddresses();
|
||||
if (acceptedArbitrators != null && !acceptedArbitrators.isEmpty()) {
|
||||
// Check also tradePrice to avoid failures after taker fee is paid caused by a too big difference
|
||||
|
@ -586,7 +602,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
availabilityResult = AvailabilityResult.OFFER_TAKEN;
|
||||
}
|
||||
|
||||
OfferAvailabilityResponse offerAvailabilityResponse = new OfferAvailabilityResponse(request.offerId, availabilityResult);
|
||||
OfferAvailabilityResponse offerAvailabilityResponse = new OfferAvailabilityResponse(request.offerId, availabilityResult, arbitratorNodeAddress);
|
||||
log.info("Send {} with offerId {} and uid {} to peer {}",
|
||||
offerAvailabilityResponse.getClass().getSimpleName(), offerAvailabilityResponse.getOfferId(),
|
||||
offerAvailabilityResponse.getUid(), peer);
|
||||
|
|
|
@ -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.offer.availability;
|
||||
|
||||
import bisq.core.arbitration.Arbitrator;
|
||||
import bisq.core.arbitration.ArbitratorManager;
|
||||
import bisq.core.trade.statistics.TradeStatistics2;
|
||||
import bisq.core.trade.statistics.TradeStatisticsManager;
|
||||
|
||||
import bisq.common.util.Tuple2;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
@Slf4j
|
||||
public class ArbitratorSelection {
|
||||
@Getter
|
||||
private static boolean isNewRuleActivated;
|
||||
|
||||
static {
|
||||
try {
|
||||
//TODO set activation data to 1 month after release
|
||||
Date activationDate = new SimpleDateFormat("dd/MM/yyyy").parse("20/11/2018");
|
||||
isNewRuleActivated = new Date().after(activationDate);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static Arbitrator getLeastUsedArbitrator(TradeStatisticsManager tradeStatisticsManager,
|
||||
ArbitratorManager arbitratorManager) {
|
||||
// We take last 100 entries from trade statistics
|
||||
List<TradeStatistics2> list = new ArrayList<>(tradeStatisticsManager.getObservableTradeStatisticsSet());
|
||||
list.sort(Comparator.comparing(TradeStatistics2::getTradeDate));
|
||||
Collections.reverse(list);
|
||||
if (!list.isEmpty()) {
|
||||
int max = Math.min(list.size(), 100);
|
||||
list = list.subList(0, max);
|
||||
}
|
||||
|
||||
// We stored only first 4 chars of arbitrators onion address
|
||||
List<String> lastAddressesUsedInTrades = list.stream()
|
||||
.filter(tradeStatistics2 -> tradeStatistics2.getExtraDataMap() != null)
|
||||
.map(tradeStatistics2 -> tradeStatistics2.getExtraDataMap().get(TradeStatistics2.ARBITRATOR_ADDRESS))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Set<String> arbitrators = arbitratorManager.getArbitratorsObservableMap().values().stream()
|
||||
.map(arbitrator -> arbitrator.getNodeAddress().getHostName())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
String result = getLeastUsedArbitrator(lastAddressesUsedInTrades, arbitrators);
|
||||
|
||||
Optional<Arbitrator> optionalArbitrator = arbitratorManager.getArbitratorsObservableMap().values().stream()
|
||||
.filter(e -> e.getNodeAddress().getHostName().equals(result))
|
||||
.findAny();
|
||||
checkArgument(optionalArbitrator.isPresent(), "optionalArbitrator has to be present");
|
||||
return optionalArbitrator.get();
|
||||
}
|
||||
|
||||
static String getLeastUsedArbitrator(List<String> lastAddressesUsedInTrades, Set<String> arbitrators) {
|
||||
checkArgument(!arbitrators.isEmpty(), "arbitrators must nto be empty");
|
||||
List<Tuple2<String, AtomicInteger>> arbitratorTuples = arbitrators.stream()
|
||||
.map(e -> new Tuple2<>(e, new AtomicInteger(0)))
|
||||
.collect(Collectors.toList());
|
||||
arbitratorTuples.forEach(tuple -> {
|
||||
int count = (int) lastAddressesUsedInTrades.stream()
|
||||
.filter(tuple.first::startsWith) // we use only first 4 chars for comparing
|
||||
.mapToInt(e -> 1)
|
||||
.count();
|
||||
tuple.second.set(count);
|
||||
});
|
||||
arbitratorTuples.sort(Comparator.comparingInt(e -> e.second.get()));
|
||||
return arbitratorTuples.get(0).first;
|
||||
}
|
||||
}
|
|
@ -27,6 +27,9 @@ import bisq.common.crypto.PubKeyRing;
|
|||
import bisq.common.taskrunner.Model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class OfferAvailabilityModel implements Model {
|
||||
@Getter
|
||||
|
@ -38,6 +41,10 @@ public class OfferAvailabilityModel implements Model {
|
|||
|
||||
private NodeAddress peerNodeAddress; // maker
|
||||
private OfferAvailabilityResponse message;
|
||||
@Nullable
|
||||
@Setter
|
||||
@Getter
|
||||
private NodeAddress selectedArbitrator;
|
||||
|
||||
public OfferAvailabilityModel(Offer offer,
|
||||
PubKeyRing pubKeyRing,
|
||||
|
|
|
@ -19,9 +19,12 @@ package bisq.core.offer.availability.tasks;
|
|||
|
||||
import bisq.core.offer.AvailabilityResult;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.availability.ArbitratorSelection;
|
||||
import bisq.core.offer.availability.OfferAvailabilityModel;
|
||||
import bisq.core.offer.messages.OfferAvailabilityResponse;
|
||||
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
|
||||
import bisq.common.taskrunner.Task;
|
||||
import bisq.common.taskrunner.TaskRunner;
|
||||
|
||||
|
@ -39,6 +42,13 @@ public class ProcessOfferAvailabilityResponse extends Task<OfferAvailabilityMode
|
|||
if (model.getOffer().getState() != Offer.State.REMOVED) {
|
||||
if (offerAvailabilityResponse.getAvailabilityResult() == AvailabilityResult.AVAILABLE) {
|
||||
model.getOffer().setState(Offer.State.AVAILABLE);
|
||||
if (ArbitratorSelection.isNewRuleActivated()) {
|
||||
NodeAddress selectedArbitrator = offerAvailabilityResponse.getArbitrator();
|
||||
if (selectedArbitrator == null)
|
||||
failed("You cannot take that offer because the offer maker is running an incompatible version.");
|
||||
else
|
||||
model.setSelectedArbitrator(selectedArbitrator);
|
||||
}
|
||||
} else {
|
||||
model.getOffer().setState(Offer.State.NOT_AVAILABLE);
|
||||
failed("Take offer attempt rejected because of: " + offerAvailabilityResponse.getAvailabilityResult());
|
||||
|
|
|
@ -20,6 +20,7 @@ package bisq.core.offer.messages;
|
|||
|
||||
import bisq.core.offer.AvailabilityResult;
|
||||
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
import bisq.network.p2p.SupportedCapabilitiesMessage;
|
||||
|
||||
import bisq.common.app.Capabilities;
|
||||
|
@ -46,12 +47,17 @@ public final class OfferAvailabilityResponse extends OfferMessage implements Sup
|
|||
@Nullable
|
||||
private final List<Integer> supportedCapabilities;
|
||||
|
||||
public OfferAvailabilityResponse(String offerId, AvailabilityResult availabilityResult) {
|
||||
// Was introduced in v 0.9.0. Might be null if msg received from node with old version
|
||||
@Nullable
|
||||
private final NodeAddress arbitrator;
|
||||
|
||||
public OfferAvailabilityResponse(String offerId, AvailabilityResult availabilityResult, NodeAddress arbitrator) {
|
||||
this(offerId,
|
||||
availabilityResult,
|
||||
Capabilities.getSupportedCapabilities(),
|
||||
Version.getP2PMessageVersion(),
|
||||
UUID.randomUUID().toString());
|
||||
UUID.randomUUID().toString(),
|
||||
arbitrator);
|
||||
}
|
||||
|
||||
|
||||
|
@ -63,10 +69,12 @@ public final class OfferAvailabilityResponse extends OfferMessage implements Sup
|
|||
AvailabilityResult availabilityResult,
|
||||
@Nullable List<Integer> supportedCapabilities,
|
||||
int messageVersion,
|
||||
@Nullable String uid) {
|
||||
@Nullable String uid,
|
||||
@Nullable NodeAddress arbitrator) {
|
||||
super(messageVersion, offerId, uid);
|
||||
this.availabilityResult = availabilityResult;
|
||||
this.supportedCapabilities = supportedCapabilities;
|
||||
this.arbitrator = arbitrator;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -77,6 +85,7 @@ public final class OfferAvailabilityResponse extends OfferMessage implements Sup
|
|||
|
||||
Optional.ofNullable(supportedCapabilities).ifPresent(e -> builder.addAllSupportedCapabilities(supportedCapabilities));
|
||||
Optional.ofNullable(uid).ifPresent(e -> builder.setUid(uid));
|
||||
Optional.ofNullable(arbitrator).ifPresent(e -> builder.setArbitrator(arbitrator.toProtoMessage()));
|
||||
|
||||
return getNetworkEnvelopeBuilder()
|
||||
.setOfferAvailabilityResponse(builder)
|
||||
|
@ -88,6 +97,7 @@ public final class OfferAvailabilityResponse extends OfferMessage implements Sup
|
|||
ProtoUtil.enumFromProto(AvailabilityResult.class, proto.getAvailabilityResult().name()),
|
||||
proto.getSupportedCapabilitiesList().isEmpty() ? null : proto.getSupportedCapabilitiesList(),
|
||||
messageVersion,
|
||||
proto.getUid().isEmpty() ? null : proto.getUid());
|
||||
proto.getUid().isEmpty() ? null : proto.getUid(),
|
||||
proto.hasArbitrator() ? NodeAddress.fromProto(proto.getArbitrator()) : null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,11 +17,13 @@
|
|||
|
||||
package bisq.core.offer.placeoffer;
|
||||
|
||||
import bisq.core.arbitration.ArbitratorManager;
|
||||
import bisq.core.btc.wallet.BsqWalletService;
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
import bisq.core.btc.wallet.TradeWalletService;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OfferBookService;
|
||||
import bisq.core.trade.statistics.TradeStatisticsManager;
|
||||
import bisq.core.user.User;
|
||||
|
||||
import bisq.common.taskrunner.Model;
|
||||
|
@ -44,6 +46,8 @@ public class PlaceOfferModel implements Model {
|
|||
private final TradeWalletService tradeWalletService;
|
||||
private final BsqWalletService bsqWalletService;
|
||||
private final OfferBookService offerBookService;
|
||||
private final ArbitratorManager arbitratorManager;
|
||||
private final TradeStatisticsManager tradeStatisticsManager;
|
||||
private final User user;
|
||||
|
||||
// Mutable
|
||||
|
@ -59,6 +63,8 @@ public class PlaceOfferModel implements Model {
|
|||
TradeWalletService tradeWalletService,
|
||||
BsqWalletService bsqWalletService,
|
||||
OfferBookService offerBookService,
|
||||
ArbitratorManager arbitratorManager,
|
||||
TradeStatisticsManager tradeStatisticsManager,
|
||||
User user) {
|
||||
this.offer = offer;
|
||||
this.reservedFundsForOffer = reservedFundsForOffer;
|
||||
|
@ -67,6 +73,8 @@ public class PlaceOfferModel implements Model {
|
|||
this.tradeWalletService = tradeWalletService;
|
||||
this.bsqWalletService = bsqWalletService;
|
||||
this.offerBookService = offerBookService;
|
||||
this.arbitratorManager = arbitratorManager;
|
||||
this.tradeStatisticsManager = tradeStatisticsManager;
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,10 +26,8 @@ import bisq.core.btc.wallet.TradeWalletService;
|
|||
import bisq.core.btc.wallet.TxBroadcaster;
|
||||
import bisq.core.btc.wallet.WalletService;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.availability.ArbitratorSelection;
|
||||
import bisq.core.offer.placeoffer.PlaceOfferModel;
|
||||
import bisq.core.trade.protocol.ArbitratorSelectionRule;
|
||||
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
|
||||
import bisq.common.UserThread;
|
||||
import bisq.common.taskrunner.Task;
|
||||
|
@ -43,8 +41,6 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class CreateMakerFeeTx extends Task<PlaceOfferModel> {
|
||||
private static final Logger log = LoggerFactory.getLogger(CreateMakerFeeTx.class);
|
||||
private Transaction tradeFeeTx = null;
|
||||
|
@ -64,11 +60,8 @@ public class CreateMakerFeeTx extends Task<PlaceOfferModel> {
|
|||
String id = offer.getId();
|
||||
BtcWalletService walletService = model.getWalletService();
|
||||
|
||||
NodeAddress selectedArbitratorNodeAddress = ArbitratorSelectionRule.select(model.getUser().getAcceptedArbitratorAddresses(),
|
||||
model.getOffer());
|
||||
log.debug("selectedArbitratorAddress " + selectedArbitratorNodeAddress);
|
||||
Arbitrator selectedArbitrator = model.getUser().getAcceptedArbitratorByAddress(selectedArbitratorNodeAddress);
|
||||
checkNotNull(selectedArbitrator, "selectedArbitrator must not be null at CreateOfferFeeTx");
|
||||
Arbitrator arbitrator = ArbitratorSelection.getLeastUsedArbitrator(model.getTradeStatisticsManager(),
|
||||
model.getArbitratorManager());
|
||||
|
||||
Address fundingAddress = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.OFFER_FUNDING).getAddress();
|
||||
Address reservedForTradeAddress = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.RESERVED_FOR_TRADE).getAddress();
|
||||
|
@ -85,7 +78,7 @@ public class CreateMakerFeeTx extends Task<PlaceOfferModel> {
|
|||
model.isUseSavingsWallet(),
|
||||
offer.getMakerFee(),
|
||||
offer.getTxFee(),
|
||||
selectedArbitrator.getBtcAddress(),
|
||||
arbitrator.getBtcAddress(),
|
||||
new TxBroadcaster.Callback() {
|
||||
@Override
|
||||
public void onSuccess(Transaction transaction) {
|
||||
|
|
|
@ -35,6 +35,8 @@ import org.bitcoinj.core.Coin;
|
|||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@Slf4j
|
||||
public final class BuyerAsMakerTrade extends BuyerTrade implements MakerTrade {
|
||||
|
||||
|
@ -46,10 +48,10 @@ public final class BuyerAsMakerTrade extends BuyerTrade implements MakerTrade {
|
|||
Coin txFee,
|
||||
Coin takeOfferFee,
|
||||
boolean isCurrencyForTakerFeeBtc,
|
||||
@Nullable NodeAddress arbitratorNodeAddress,
|
||||
Storage<? extends TradableList> storage,
|
||||
BtcWalletService btcWalletService) {
|
||||
super(offer, txFee, takeOfferFee, isCurrencyForTakerFeeBtc,
|
||||
storage, btcWalletService);
|
||||
super(offer, txFee, takeOfferFee, isCurrencyForTakerFeeBtc, arbitratorNodeAddress, storage, btcWalletService);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -69,11 +71,12 @@ public final class BuyerAsMakerTrade extends BuyerTrade implements MakerTrade {
|
|||
BtcWalletService btcWalletService,
|
||||
CoreProtoResolver coreProtoResolver) {
|
||||
PB.Trade proto = buyerAsMakerTradeProto.getTrade();
|
||||
final BuyerAsMakerTrade trade = new BuyerAsMakerTrade(
|
||||
BuyerAsMakerTrade trade = new BuyerAsMakerTrade(
|
||||
Offer.fromProto(proto.getOffer()),
|
||||
Coin.valueOf(proto.getTxFeeAsLong()),
|
||||
Coin.valueOf(proto.getTakerFeeAsLong()),
|
||||
proto.getIsCurrencyForTakerFeeBtc(),
|
||||
proto.hasArbitratorNodeAddress() ? NodeAddress.fromProto(proto.getArbitratorNodeAddress()) : null,
|
||||
storage,
|
||||
btcWalletService);
|
||||
|
||||
|
|
|
@ -33,6 +33,8 @@ import org.bitcoinj.core.Coin;
|
|||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
@Slf4j
|
||||
|
@ -49,10 +51,11 @@ public final class BuyerAsTakerTrade extends BuyerTrade implements TakerTrade {
|
|||
boolean isCurrencyForTakerFeeBtc,
|
||||
long tradePrice,
|
||||
NodeAddress tradingPeerNodeAddress,
|
||||
@Nullable NodeAddress arbitratorNodeAddress,
|
||||
Storage<? extends TradableList> storage,
|
||||
BtcWalletService btcWalletService) {
|
||||
super(offer, tradeAmount, txFee, takerFee, isCurrencyForTakerFeeBtc, tradePrice,
|
||||
tradingPeerNodeAddress, storage, btcWalletService);
|
||||
super(offer, tradeAmount, txFee, takerFee, isCurrencyForTakerFeeBtc, tradePrice, tradingPeerNodeAddress,
|
||||
arbitratorNodeAddress, storage, btcWalletService);
|
||||
}
|
||||
|
||||
|
||||
|
@ -81,6 +84,7 @@ public final class BuyerAsTakerTrade extends BuyerTrade implements TakerTrade {
|
|||
proto.getIsCurrencyForTakerFeeBtc(),
|
||||
proto.getTradePrice(),
|
||||
proto.hasTradingPeerNodeAddress() ? NodeAddress.fromProto(proto.getTradingPeerNodeAddress()) : null,
|
||||
proto.hasArbitratorNodeAddress() ? NodeAddress.fromProto(proto.getArbitratorNodeAddress()) : null,
|
||||
storage,
|
||||
btcWalletService),
|
||||
proto,
|
||||
|
|
|
@ -31,6 +31,8 @@ import org.bitcoinj.core.Coin;
|
|||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
|
@ -43,19 +45,21 @@ public abstract class BuyerTrade extends Trade {
|
|||
boolean isCurrencyForTakerFeeBtc,
|
||||
long tradePrice,
|
||||
NodeAddress tradingPeerNodeAddress,
|
||||
@Nullable NodeAddress arbitratorNodeAddress,
|
||||
Storage<? extends TradableList> storage,
|
||||
BtcWalletService btcWalletService) {
|
||||
super(offer, tradeAmount, txFee, takerFee, isCurrencyForTakerFeeBtc, tradePrice,
|
||||
tradingPeerNodeAddress, storage, btcWalletService);
|
||||
tradingPeerNodeAddress, arbitratorNodeAddress, storage, btcWalletService);
|
||||
}
|
||||
|
||||
BuyerTrade(Offer offer,
|
||||
Coin txFee,
|
||||
Coin takerFee,
|
||||
boolean isCurrencyForTakerFeeBtc,
|
||||
@Nullable NodeAddress arbitratorNodeAddress,
|
||||
Storage<? extends TradableList> storage,
|
||||
BtcWalletService btcWalletService) {
|
||||
super(offer, txFee, takerFee, isCurrencyForTakerFeeBtc, storage, btcWalletService);
|
||||
super(offer, txFee, takerFee, isCurrencyForTakerFeeBtc, arbitratorNodeAddress, storage, btcWalletService);
|
||||
}
|
||||
|
||||
public void onFiatPaymentStarted(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
||||
|
|
|
@ -35,6 +35,8 @@ import org.bitcoinj.core.Coin;
|
|||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@Slf4j
|
||||
public final class SellerAsMakerTrade extends SellerTrade implements MakerTrade {
|
||||
|
||||
|
@ -46,9 +48,10 @@ public final class SellerAsMakerTrade extends SellerTrade implements MakerTrade
|
|||
Coin txFee,
|
||||
Coin takerFee,
|
||||
boolean isCurrencyForTakerFeeBtc,
|
||||
@Nullable NodeAddress arbitratorNodeAddress,
|
||||
Storage<? extends TradableList> storage,
|
||||
BtcWalletService btcWalletService) {
|
||||
super(offer, txFee, takerFee, isCurrencyForTakerFeeBtc, storage, btcWalletService);
|
||||
super(offer, txFee, takerFee, isCurrencyForTakerFeeBtc, arbitratorNodeAddress, storage, btcWalletService);
|
||||
}
|
||||
|
||||
|
||||
|
@ -69,11 +72,12 @@ public final class SellerAsMakerTrade extends SellerTrade implements MakerTrade
|
|||
BtcWalletService btcWalletService,
|
||||
CoreProtoResolver coreProtoResolver) {
|
||||
PB.Trade proto = sellerAsMakerTradeProto.getTrade();
|
||||
final SellerAsMakerTrade trade = new SellerAsMakerTrade(
|
||||
SellerAsMakerTrade trade = new SellerAsMakerTrade(
|
||||
Offer.fromProto(proto.getOffer()),
|
||||
Coin.valueOf(proto.getTxFeeAsLong()),
|
||||
Coin.valueOf(proto.getTakerFeeAsLong()),
|
||||
proto.getIsCurrencyForTakerFeeBtc(),
|
||||
proto.hasArbitratorNodeAddress() ? NodeAddress.fromProto(proto.getArbitratorNodeAddress()) : null,
|
||||
storage,
|
||||
btcWalletService);
|
||||
|
||||
|
|
|
@ -33,6 +33,8 @@ import org.bitcoinj.core.Coin;
|
|||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
@Slf4j
|
||||
|
@ -49,10 +51,11 @@ public final class SellerAsTakerTrade extends SellerTrade implements TakerTrade
|
|||
boolean isCurrencyForTakerFeeBtc,
|
||||
long tradePrice,
|
||||
NodeAddress tradingPeerNodeAddress,
|
||||
@Nullable NodeAddress arbitratorNodeAddress,
|
||||
Storage<? extends TradableList> storage,
|
||||
BtcWalletService btcWalletService) {
|
||||
super(offer, tradeAmount, txFee, takerFee, isCurrencyForTakerFeeBtc, tradePrice,
|
||||
tradingPeerNodeAddress, storage, btcWalletService);
|
||||
tradingPeerNodeAddress, arbitratorNodeAddress, storage, btcWalletService);
|
||||
}
|
||||
|
||||
|
||||
|
@ -81,6 +84,7 @@ public final class SellerAsTakerTrade extends SellerTrade implements TakerTrade
|
|||
proto.getIsCurrencyForTakerFeeBtc(),
|
||||
proto.getTradePrice(),
|
||||
proto.hasTradingPeerNodeAddress() ? NodeAddress.fromProto(proto.getTradingPeerNodeAddress()) : null,
|
||||
proto.hasArbitratorNodeAddress() ? NodeAddress.fromProto(proto.getArbitratorNodeAddress()) : null,
|
||||
storage,
|
||||
btcWalletService),
|
||||
proto,
|
||||
|
|
|
@ -31,6 +31,8 @@ import org.bitcoinj.core.Coin;
|
|||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
@Slf4j
|
||||
|
@ -42,19 +44,21 @@ public abstract class SellerTrade extends Trade {
|
|||
boolean isCurrencyForTakerFeeBtc,
|
||||
long tradePrice,
|
||||
NodeAddress tradingPeerNodeAddress,
|
||||
@Nullable NodeAddress arbitratorNodeAddress,
|
||||
Storage<? extends TradableList> storage,
|
||||
BtcWalletService btcWalletService) {
|
||||
super(offer, tradeAmount, txFee, takerFee, isCurrencyForTakerFeeBtc, tradePrice,
|
||||
tradingPeerNodeAddress, storage, btcWalletService);
|
||||
tradingPeerNodeAddress, arbitratorNodeAddress, storage, btcWalletService);
|
||||
}
|
||||
|
||||
SellerTrade(Offer offer,
|
||||
Coin txFee,
|
||||
Coin takeOfferFee,
|
||||
boolean isCurrencyForTakerFeeBtc,
|
||||
@Nullable NodeAddress arbitratorNodeAddress,
|
||||
Storage<? extends TradableList> storage,
|
||||
BtcWalletService btcWalletService) {
|
||||
super(offer, txFee, takeOfferFee, isCurrencyForTakerFeeBtc, storage, btcWalletService);
|
||||
super(offer, txFee, takeOfferFee, isCurrencyForTakerFeeBtc, arbitratorNodeAddress, storage, btcWalletService);
|
||||
}
|
||||
|
||||
public void onFiatPaymentReceived(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package bisq.core.trade;
|
||||
|
||||
import bisq.core.arbitration.Arbitrator;
|
||||
import bisq.core.arbitration.ArbitratorManager;
|
||||
import bisq.core.arbitration.Mediator;
|
||||
import bisq.core.btc.wallet.BsqWalletService;
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
|
@ -29,18 +30,21 @@ import bisq.core.monetary.Volume;
|
|||
import bisq.core.offer.Offer;
|
||||
import bisq.core.offer.OfferUtil;
|
||||
import bisq.core.offer.OpenOfferManager;
|
||||
import bisq.core.offer.availability.ArbitratorSelection;
|
||||
import bisq.core.payment.AccountAgeWitnessService;
|
||||
import bisq.core.payment.payload.PaymentMethod;
|
||||
import bisq.core.proto.CoreProtoResolver;
|
||||
import bisq.core.trade.protocol.ProcessModel;
|
||||
import bisq.core.trade.protocol.TradeProtocol;
|
||||
import bisq.core.trade.statistics.ReferralIdService;
|
||||
import bisq.core.trade.statistics.TradeStatisticsManager;
|
||||
import bisq.core.user.User;
|
||||
|
||||
import bisq.network.p2p.DecryptedMessageWithPubKey;
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
import bisq.network.p2p.P2PService;
|
||||
|
||||
import bisq.common.UserThread;
|
||||
import bisq.common.app.Log;
|
||||
import bisq.common.crypto.KeyRing;
|
||||
import bisq.common.crypto.PubKeyRing;
|
||||
|
@ -373,6 +377,7 @@ public abstract class Trade implements Tradable, Model {
|
|||
Coin txFee,
|
||||
Coin takerFee,
|
||||
boolean isCurrencyForTakerFeeBtc,
|
||||
@Nullable NodeAddress arbitratorNodeAddress,
|
||||
Storage<? extends TradableList> storage,
|
||||
BtcWalletService btcWalletService) {
|
||||
this.offer = offer;
|
||||
|
@ -381,6 +386,7 @@ public abstract class Trade implements Tradable, Model {
|
|||
this.isCurrencyForTakerFeeBtc = isCurrencyForTakerFeeBtc;
|
||||
this.storage = storage;
|
||||
this.btcWalletService = btcWalletService;
|
||||
this.arbitratorNodeAddress = arbitratorNodeAddress;
|
||||
|
||||
txFeeAsLong = txFee.value;
|
||||
takerFeeAsLong = takerFee.value;
|
||||
|
@ -398,10 +404,11 @@ public abstract class Trade implements Tradable, Model {
|
|||
boolean isCurrencyForTakerFeeBtc,
|
||||
long tradePrice,
|
||||
NodeAddress tradingPeerNodeAddress,
|
||||
@Nullable NodeAddress arbitratorNodeAddress,
|
||||
Storage<? extends TradableList> storage,
|
||||
BtcWalletService btcWalletService) {
|
||||
|
||||
this(offer, txFee, takerFee, isCurrencyForTakerFeeBtc, storage, btcWalletService);
|
||||
this(offer, txFee, takerFee, isCurrencyForTakerFeeBtc, arbitratorNodeAddress, storage, btcWalletService);
|
||||
this.tradePrice = tradePrice;
|
||||
this.tradingPeerNodeAddress = tradingPeerNodeAddress;
|
||||
|
||||
|
@ -493,6 +500,8 @@ public abstract class Trade implements Tradable, Model {
|
|||
User user,
|
||||
FilterManager filterManager,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
TradeStatisticsManager tradeStatisticsManager,
|
||||
ArbitratorManager arbitratorManager,
|
||||
KeyRing keyRing,
|
||||
boolean useSavingsWallet,
|
||||
Coin fundsNeededForTrade) {
|
||||
|
@ -508,10 +517,22 @@ public abstract class Trade implements Tradable, Model {
|
|||
user,
|
||||
filterManager,
|
||||
accountAgeWitnessService,
|
||||
tradeStatisticsManager,
|
||||
arbitratorManager,
|
||||
keyRing,
|
||||
useSavingsWallet,
|
||||
fundsNeededForTrade);
|
||||
|
||||
if (ArbitratorSelection.isNewRuleActivated()) {
|
||||
Optional<Arbitrator> optionalArbitrator = processModel.getArbitratorManager().getArbitratorByNodeAddress(arbitratorNodeAddress);
|
||||
if (optionalArbitrator.isPresent()) {
|
||||
Arbitrator arbitrator = optionalArbitrator.get();
|
||||
arbitratorBtcPubKey = arbitrator.getBtcPubKey();
|
||||
arbitratorPubKeyRing = arbitrator.getPubKeyRing();
|
||||
UserThread.runAfter(() -> this.persist(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
createTradeProtocol();
|
||||
|
||||
// If we have already received a msg we apply it.
|
||||
|
@ -666,6 +687,7 @@ public abstract class Trade implements Tradable, Model {
|
|||
errorMessageProperty.set(errorMessage);
|
||||
}
|
||||
|
||||
//TODO can be removed after new rule is actiavted
|
||||
@SuppressWarnings("NullableProblems")
|
||||
public void setArbitratorNodeAddress(NodeAddress arbitratorNodeAddress) {
|
||||
this.arbitratorNodeAddress = arbitratorNodeAddress;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package bisq.core.trade;
|
||||
|
||||
import bisq.core.arbitration.ArbitratorManager;
|
||||
import bisq.core.btc.exceptions.AddressEntryException;
|
||||
import bisq.core.btc.model.AddressEntry;
|
||||
import bisq.core.btc.wallet.BsqWalletService;
|
||||
|
@ -116,6 +117,7 @@ public class TradeManager implements PersistedDataHost {
|
|||
private final TradeStatisticsManager tradeStatisticsManager;
|
||||
private final ReferralIdService referralIdService;
|
||||
private final AccountAgeWitnessService accountAgeWitnessService;
|
||||
private final ArbitratorManager arbitratorManager;
|
||||
private final Clock clock;
|
||||
|
||||
private final Storage<TradableList<Trade>> tradableListStorage;
|
||||
|
@ -149,6 +151,7 @@ public class TradeManager implements PersistedDataHost {
|
|||
ReferralIdService referralIdService,
|
||||
PersistenceProtoResolver persistenceProtoResolver,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
ArbitratorManager arbitratorManager,
|
||||
Clock clock,
|
||||
@Named(Storage.STORAGE_DIR) File storageDir) {
|
||||
this.user = user;
|
||||
|
@ -165,6 +168,7 @@ public class TradeManager implements PersistedDataHost {
|
|||
this.tradeStatisticsManager = tradeStatisticsManager;
|
||||
this.referralIdService = referralIdService;
|
||||
this.accountAgeWitnessService = accountAgeWitnessService;
|
||||
this.arbitratorManager = arbitratorManager;
|
||||
this.clock = clock;
|
||||
|
||||
tradableListStorage = new Storage<>(storageDir, persistenceProtoResolver);
|
||||
|
@ -313,14 +317,16 @@ public class TradeManager implements PersistedDataHost {
|
|||
|
||||
Optional<OpenOffer> openOfferOptional = openOfferManager.getOpenOfferById(payDepositRequest.getTradeId());
|
||||
if (openOfferOptional.isPresent() && openOfferOptional.get().getState() == OpenOffer.State.AVAILABLE) {
|
||||
Offer offer = openOfferOptional.get().getOffer();
|
||||
openOfferManager.reserveOpenOffer(openOfferOptional.get());
|
||||
OpenOffer openOffer = openOfferOptional.get();
|
||||
Offer offer = openOffer.getOffer();
|
||||
openOfferManager.reserveOpenOffer(openOffer);
|
||||
Trade trade;
|
||||
if (offer.isBuyOffer())
|
||||
trade = new BuyerAsMakerTrade(offer,
|
||||
Coin.valueOf(payDepositRequest.getTxFee()),
|
||||
Coin.valueOf(payDepositRequest.getTakerFee()),
|
||||
payDepositRequest.isCurrencyForTakerFeeBtc(),
|
||||
openOffer.getArbitratorNodeAddress(),
|
||||
tradableListStorage,
|
||||
btcWalletService);
|
||||
else
|
||||
|
@ -328,6 +334,7 @@ public class TradeManager implements PersistedDataHost {
|
|||
Coin.valueOf(payDepositRequest.getTxFee()),
|
||||
Coin.valueOf(payDepositRequest.getTakerFee()),
|
||||
payDepositRequest.isCurrencyForTakerFeeBtc(),
|
||||
openOffer.getArbitratorNodeAddress(),
|
||||
tradableListStorage,
|
||||
btcWalletService);
|
||||
|
||||
|
@ -356,6 +363,8 @@ public class TradeManager implements PersistedDataHost {
|
|||
user,
|
||||
filterManager,
|
||||
accountAgeWitnessService,
|
||||
tradeStatisticsManager,
|
||||
arbitratorManager,
|
||||
keyRing,
|
||||
useSavingsWallet,
|
||||
fundsNeededForTrade);
|
||||
|
@ -436,6 +445,7 @@ public class TradeManager implements PersistedDataHost {
|
|||
isCurrencyForTakerFeeBtc,
|
||||
tradePrice,
|
||||
model.getPeerNodeAddress(),
|
||||
model.getSelectedArbitrator(),
|
||||
tradableListStorage,
|
||||
btcWalletService);
|
||||
else
|
||||
|
@ -446,6 +456,7 @@ public class TradeManager implements PersistedDataHost {
|
|||
isCurrencyForTakerFeeBtc,
|
||||
tradePrice,
|
||||
model.getPeerNodeAddress(),
|
||||
model.getSelectedArbitrator(),
|
||||
tradableListStorage,
|
||||
btcWalletService);
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@ import bisq.core.trade.protocol.tasks.maker.MakerProcessDepositTxPublishedMessag
|
|||
import bisq.core.trade.protocol.tasks.maker.MakerProcessPayDepositRequest;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerSendPublishDepositTxRequest;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerSetupDepositTxListener;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerVerifyArbitratorSelection;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerVerifyMediatorSelection;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerVerifyTakerAccount;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerVerifyTakerFeePayment;
|
||||
|
@ -132,7 +131,6 @@ public class BuyerAsMakerProtocol extends TradeProtocol implements BuyerProtocol
|
|||
taskRunner.addTasks(
|
||||
MakerProcessPayDepositRequest.class,
|
||||
CheckIfPeerIsBanned.class,
|
||||
MakerVerifyArbitratorSelection.class,
|
||||
MakerVerifyMediatorSelection.class,
|
||||
MakerVerifyTakerAccount.class,
|
||||
VerifyPeersAccountAgeWitness.class,
|
||||
|
|
|
@ -18,9 +18,10 @@
|
|||
package bisq.core.trade.protocol;
|
||||
|
||||
import bisq.core.app.BisqEnvironment;
|
||||
import bisq.core.arbitration.ArbitratorManager;
|
||||
import bisq.core.btc.model.RawTransactionInput;
|
||||
import bisq.core.btc.wallet.BsqWalletService;
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
import bisq.core.btc.model.RawTransactionInput;
|
||||
import bisq.core.btc.wallet.TradeWalletService;
|
||||
import bisq.core.filter.FilterManager;
|
||||
import bisq.core.network.MessageState;
|
||||
|
@ -35,6 +36,7 @@ import bisq.core.trade.Trade;
|
|||
import bisq.core.trade.TradeManager;
|
||||
import bisq.core.trade.messages.TradeMessage;
|
||||
import bisq.core.trade.statistics.ReferralIdService;
|
||||
import bisq.core.trade.statistics.TradeStatisticsManager;
|
||||
import bisq.core.user.User;
|
||||
|
||||
import bisq.network.p2p.AckMessage;
|
||||
|
@ -82,6 +84,8 @@ public class ProcessModel implements Model, PersistablePayload {
|
|||
transient private User user;
|
||||
transient private FilterManager filterManager;
|
||||
transient private AccountAgeWitnessService accountAgeWitnessService;
|
||||
transient private TradeStatisticsManager tradeStatisticsManager;
|
||||
transient private ArbitratorManager arbitratorManager;
|
||||
transient private KeyRing keyRing;
|
||||
transient private P2PService p2PService;
|
||||
transient private ReferralIdService referralIdService;
|
||||
|
@ -229,6 +233,8 @@ public class ProcessModel implements Model, PersistablePayload {
|
|||
User user,
|
||||
FilterManager filterManager,
|
||||
AccountAgeWitnessService accountAgeWitnessService,
|
||||
TradeStatisticsManager tradeStatisticsManager,
|
||||
ArbitratorManager arbitratorManager,
|
||||
KeyRing keyRing,
|
||||
boolean useSavingsWallet,
|
||||
Coin fundsNeededForTrade) {
|
||||
|
@ -242,6 +248,8 @@ public class ProcessModel implements Model, PersistablePayload {
|
|||
this.user = user;
|
||||
this.filterManager = filterManager;
|
||||
this.accountAgeWitnessService = accountAgeWitnessService;
|
||||
this.tradeStatisticsManager = tradeStatisticsManager;
|
||||
this.arbitratorManager = arbitratorManager;
|
||||
this.keyRing = keyRing;
|
||||
this.p2PService = p2PService;
|
||||
this.useSavingsWallet = useSavingsWallet;
|
||||
|
|
|
@ -32,7 +32,6 @@ import bisq.core.trade.protocol.tasks.maker.MakerProcessDepositTxPublishedMessag
|
|||
import bisq.core.trade.protocol.tasks.maker.MakerProcessPayDepositRequest;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerSendPublishDepositTxRequest;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerSetupDepositTxListener;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerVerifyArbitratorSelection;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerVerifyMediatorSelection;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerVerifyTakerAccount;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerVerifyTakerFeePayment;
|
||||
|
@ -127,7 +126,6 @@ public class SellerAsMakerProtocol extends TradeProtocol implements SellerProtoc
|
|||
taskRunner.addTasks(
|
||||
MakerProcessPayDepositRequest.class,
|
||||
CheckIfPeerIsBanned.class,
|
||||
MakerVerifyArbitratorSelection.class,
|
||||
MakerVerifyMediatorSelection.class,
|
||||
MakerVerifyTakerAccount.class,
|
||||
VerifyPeersAccountAgeWitness.class,
|
||||
|
|
|
@ -22,14 +22,18 @@ import bisq.core.offer.OfferPayload;
|
|||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.statistics.TradeStatistics2;
|
||||
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
|
||||
import bisq.common.taskrunner.TaskRunner;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
|
||||
@Slf4j
|
||||
public class PublishTradeStatistics extends TradeTask {
|
||||
public PublishTradeStatistics(TaskRunner taskHandler, Trade trade) {
|
||||
super(taskHandler, trade);
|
||||
|
@ -40,12 +44,18 @@ public class PublishTradeStatistics extends TradeTask {
|
|||
try {
|
||||
runInterceptHook();
|
||||
if (trade.getDepositTx() != null) {
|
||||
Map<String, String> extraDataMap = null;
|
||||
Map<String, String> extraDataMap = new HashMap<>();
|
||||
if (processModel.getReferralIdService().getOptionalReferralId().isPresent()) {
|
||||
extraDataMap = new HashMap<>();
|
||||
extraDataMap.put(OfferPayload.REFERRAL_ID, processModel.getReferralIdService().getOptionalReferralId().get());
|
||||
}
|
||||
|
||||
NodeAddress arbitratorNodeAddress = trade.getArbitratorNodeAddress();
|
||||
if (arbitratorNodeAddress != null) {
|
||||
// The first 4 chars are sufficient to identify an arbitrator
|
||||
String address = arbitratorNodeAddress.getHostName().substring(0, 4);
|
||||
extraDataMap.put(TradeStatistics2.ARBITRATOR_ADDRESS, address);
|
||||
}
|
||||
|
||||
Offer offer = trade.getOffer();
|
||||
checkNotNull(offer, "offer must not ne null");
|
||||
checkNotNull(trade.getTradeAmount(), "trade.getTradeAmount() must not ne null");
|
||||
|
|
|
@ -25,12 +25,9 @@ import bisq.core.btc.wallet.BtcWalletService;
|
|||
import bisq.core.btc.wallet.TradeWalletService;
|
||||
import bisq.core.btc.wallet.TxBroadcaster;
|
||||
import bisq.core.btc.wallet.WalletService;
|
||||
import bisq.core.offer.availability.ArbitratorSelection;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.protocol.ArbitratorSelectionRule;
|
||||
import bisq.core.trade.protocol.tasks.TradeTask;
|
||||
import bisq.core.user.User;
|
||||
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
|
||||
import bisq.common.UserThread;
|
||||
import bisq.common.taskrunner.TaskRunner;
|
||||
|
@ -42,8 +39,6 @@ import lombok.extern.slf4j.Slf4j;
|
|||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@Slf4j
|
||||
public class CreateTakerFeeTx extends TradeTask {
|
||||
private Transaction tradeFeeTx;
|
||||
|
@ -58,13 +53,8 @@ public class CreateTakerFeeTx extends TradeTask {
|
|||
try {
|
||||
runInterceptHook();
|
||||
|
||||
User user = processModel.getUser();
|
||||
NodeAddress selectedArbitratorNodeAddress = ArbitratorSelectionRule.select(user.getAcceptedArbitratorAddresses(),
|
||||
processModel.getOffer());
|
||||
log.debug("selectedArbitratorAddress " + selectedArbitratorNodeAddress);
|
||||
Arbitrator selectedArbitrator = user.getAcceptedArbitratorByAddress(selectedArbitratorNodeAddress);
|
||||
checkNotNull(selectedArbitrator, "selectedArbitrator must not be null at CreateTakeOfferFeeTx");
|
||||
|
||||
Arbitrator arbitrator = ArbitratorSelection.getLeastUsedArbitrator(processModel.getTradeStatisticsManager(),
|
||||
processModel.getArbitratorManager());
|
||||
BtcWalletService walletService = processModel.getBtcWalletService();
|
||||
String id = processModel.getOffer().getId();
|
||||
AddressEntry addressEntry = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.OFFER_FUNDING);
|
||||
|
@ -83,7 +73,7 @@ public class CreateTakerFeeTx extends TradeTask {
|
|||
processModel.isUseSavingsWallet(),
|
||||
trade.getTakerFee(),
|
||||
trade.getTxFee(),
|
||||
selectedArbitrator.getBtcAddress(),
|
||||
arbitrator.getBtcAddress(),
|
||||
new TxBroadcaster.Callback() {
|
||||
@Override
|
||||
public void onSuccess(Transaction transaction) {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package bisq.core.trade.protocol.tasks.taker;
|
||||
|
||||
import bisq.core.offer.availability.ArbitratorSelection;
|
||||
import bisq.core.trade.Trade;
|
||||
import bisq.core.trade.protocol.ArbitratorSelectionRule;
|
||||
import bisq.core.trade.protocol.tasks.TradeTask;
|
||||
|
@ -37,7 +38,10 @@ public class TakerSelectArbitrator extends TradeTask {
|
|||
try {
|
||||
runInterceptHook();
|
||||
|
||||
trade.setArbitratorNodeAddress(ArbitratorSelectionRule.select(processModel.getUser().getAcceptedArbitratorAddresses(), processModel.getOffer()));
|
||||
// TODO can be removed after new rule is activated
|
||||
if (!ArbitratorSelection.isNewRuleActivated()) {
|
||||
trade.setArbitratorNodeAddress(ArbitratorSelectionRule.select(processModel.getUser().getAcceptedArbitratorAddresses(), processModel.getOffer()));
|
||||
}
|
||||
|
||||
complete();
|
||||
} catch (Throwable t) {
|
||||
|
|
|
@ -66,6 +66,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
@Slf4j
|
||||
@Value
|
||||
public final class TradeStatistics2 implements LazyProcessedPayload, PersistableNetworkPayload, PersistableEnvelope, CapabilityRequiringPayload {
|
||||
public static final String ARBITRATOR_ADDRESS = "arbAddr";
|
||||
|
||||
private final OfferPayload.Direction direction;
|
||||
private final String baseCurrency;
|
||||
private final String counterCurrency;
|
||||
|
|
|
@ -380,6 +380,7 @@ public final class User implements PersistedDataHost {
|
|||
return userPayload.getRegisteredMediator();
|
||||
}
|
||||
|
||||
//TODO
|
||||
@Nullable
|
||||
public List<Arbitrator> getAcceptedArbitrators() {
|
||||
return userPayload.getAcceptedArbitrators();
|
||||
|
|
|
@ -828,7 +828,6 @@ settings.tab.about=About
|
|||
setting.preferences.general=General preferences
|
||||
setting.preferences.explorer=Bitcoin block explorer:
|
||||
setting.preferences.deviation=Max. deviation from market price:
|
||||
setting.preferences.autoSelectArbitrators=Auto select arbitrators:
|
||||
setting.preferences.avoidStandbyMode=Avoid standby mode:
|
||||
setting.preferences.deviationToLarge=Values higher than {0}% are not allowed.
|
||||
setting.preferences.txFee=Withdrawal transaction fee (satoshis/byte):
|
||||
|
@ -941,7 +940,6 @@ Bisq is a decentralized exchange – meaning all of your data is kept on your co
|
|||
|
||||
account.menu.paymentAccount=National currency accounts
|
||||
account.menu.altCoinsAccountView=Altcoin accounts
|
||||
account.menu.arbitratorSelection=Arbitrator selection
|
||||
account.menu.password=Wallet password
|
||||
account.menu.seedWords=Wallet seed
|
||||
account.menu.backup=Backup
|
||||
|
@ -1649,7 +1647,6 @@ offerDetailsWindow.agree=I agree:
|
|||
offerDetailsWindow.tac=Terms and conditions:
|
||||
offerDetailsWindow.confirm.maker=Confirm: Place offer to {0} bitcoin
|
||||
offerDetailsWindow.confirm.taker=Confirm: Take offer to {0} bitcoin
|
||||
offerDetailsWindow.warn.noArbitrator=You have no arbitrator selected.\nPlease select at least one arbitrator.
|
||||
offerDetailsWindow.creationDate=Creation date:
|
||||
offerDetailsWindow.makersOnion=Maker's onion address:
|
||||
|
||||
|
@ -1783,8 +1780,7 @@ popup.warning.tradePeriod.halfReached=Your trade with ID {0} has reached the hal
|
|||
popup.warning.tradePeriod.ended=Your trade with ID {0} has reached the max. allowed trading period and is not completed.\n\nThe trade period ended on {1}\n\nPlease check your trade at \"Portfolio/Open trades\" for contacting the arbitrator.
|
||||
popup.warning.noTradingAccountSetup.headline=You have not setup a trading account
|
||||
popup.warning.noTradingAccountSetup.msg=You need to setup a national currency or altcoin account before you can create an offer.\nDo you want to setup an account?
|
||||
popup.warning.noArbitratorSelected.headline=You don't have an arbitrator selected.
|
||||
popup.warning.noArbitratorSelected.msg=You need to setup at least one arbitrator to be able to trade.\nDo you want to do this now?
|
||||
popup.warning.noArbitratorsAvailable=There are no arbitrators available.
|
||||
popup.warning.notFullyConnected=You need to wait until you are fully connected to the network.\nThat might take up to about 2 minutes at startup.
|
||||
popup.warning.notSufficientConnectionsToBtcNetwork=You need to wait until you have at least {0} connections to the Bitcoin network.
|
||||
popup.warning.downloadNotComplete=You need to wait until the download of missing Bitcoin blocks is complete.
|
||||
|
@ -1952,7 +1948,6 @@ txIdTextField.blockExplorerIcon.tooltip=Open a blockchain explorer with that tra
|
|||
|
||||
navigation.account=\"Account\"
|
||||
navigation.account.walletSeed=\"Account/Wallet seed\"
|
||||
navigation.arbitratorSelection=\"Arbitrator selection\"
|
||||
navigation.funds.availableForWithdrawal=\"Fund/Send funds\"
|
||||
navigation.portfolio.myOpenOffers=\"Portfolio/My open offers\"
|
||||
navigation.portfolio.pending=\"Portfolio/Open trades\"
|
||||
|
|
|
@ -37,7 +37,7 @@ public class OpenOfferManagerTest {
|
|||
final OpenOfferManager manager = new OpenOfferManager(null, null, p2PService,
|
||||
null, null, null, offerBookService,
|
||||
null, null, null, null,
|
||||
null);
|
||||
null, null, null);
|
||||
|
||||
AtomicBoolean startEditOfferSuccessful = new AtomicBoolean(false);
|
||||
|
||||
|
@ -72,7 +72,7 @@ public class OpenOfferManagerTest {
|
|||
final OpenOfferManager manager = new OpenOfferManager(null, null, p2PService,
|
||||
null, null, null, offerBookService,
|
||||
null, null, null, null,
|
||||
null);
|
||||
null, null, null);
|
||||
|
||||
AtomicBoolean startEditOfferSuccessful = new AtomicBoolean(false);
|
||||
|
||||
|
@ -99,7 +99,7 @@ public class OpenOfferManagerTest {
|
|||
final OpenOfferManager manager = new OpenOfferManager(null, null, p2PService,
|
||||
null, null, null, offerBookService,
|
||||
null, null, null, null,
|
||||
null);
|
||||
null, null, null);
|
||||
|
||||
AtomicBoolean startEditOfferSuccessful = new AtomicBoolean(false);
|
||||
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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.offer.availability;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class ArbitratorSelectionTest {
|
||||
@Test
|
||||
public void testGetLeastUsedArbitrator() {
|
||||
// We get least used selected
|
||||
List<String> lastAddressesUsedInTrades = Arrays.asList("arb1", "arb2", "arb1");
|
||||
Set<String> arbitrators = new HashSet<>(Arrays.asList("arb1", "arb2"));
|
||||
String result = ArbitratorSelection.getLeastUsedArbitrator(lastAddressesUsedInTrades, arbitrators);
|
||||
assertEquals("arb2", result);
|
||||
|
||||
// if all are same we use first according to alphanumeric sorting
|
||||
lastAddressesUsedInTrades = Arrays.asList("arb1", "arb2", "arb3");
|
||||
arbitrators = new HashSet<>(Arrays.asList("arb1", "arb2", "arb3"));
|
||||
result = ArbitratorSelection.getLeastUsedArbitrator(lastAddressesUsedInTrades, arbitrators);
|
||||
assertEquals("arb1", result);
|
||||
lastAddressesUsedInTrades = Arrays.asList("xxx", "ccc", "aaa");
|
||||
arbitrators = new HashSet<>(Arrays.asList("aaa", "ccc", "xxx"));
|
||||
result = ArbitratorSelection.getLeastUsedArbitrator(lastAddressesUsedInTrades, arbitrators);
|
||||
assertEquals("aaa", result);
|
||||
lastAddressesUsedInTrades = Arrays.asList("333", "000", "111");
|
||||
arbitrators = new HashSet<>(Arrays.asList("111", "333", "000"));
|
||||
result = ArbitratorSelection.getLeastUsedArbitrator(lastAddressesUsedInTrades, arbitrators);
|
||||
assertEquals("000", result);
|
||||
|
||||
// if winner is not in our arb list we use our arb from arbitrators even if never used in trades
|
||||
lastAddressesUsedInTrades = Arrays.asList("arb1", "arb2", "arb3");
|
||||
arbitrators = new HashSet<>(Arrays.asList("arb4"));
|
||||
result = ArbitratorSelection.getLeastUsedArbitrator(lastAddressesUsedInTrades, arbitrators);
|
||||
assertEquals("arb4", result);
|
||||
|
||||
// if winner (arb2) is not in our arb list we use our arb from arbitrators
|
||||
lastAddressesUsedInTrades = Arrays.asList("arb1", "arb1", "arb1", "arb2");
|
||||
arbitrators = new HashSet<>(Arrays.asList("arb1"));
|
||||
result = ArbitratorSelection.getLeastUsedArbitrator(lastAddressesUsedInTrades, arbitrators);
|
||||
assertEquals("arb1", result);
|
||||
|
||||
// arb1 is used least
|
||||
lastAddressesUsedInTrades = Arrays.asList("arb1", "arb2", "arb2", "arb2", "arb1", "arb1", "arb2");
|
||||
arbitrators = new HashSet<>(Arrays.asList("arb1", "arb2"));
|
||||
result = ArbitratorSelection.getLeastUsedArbitrator(lastAddressesUsedInTrades, arbitrators);
|
||||
assertEquals("arb1", result);
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
* 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.desktop.main.account.content.arbitratorselection;
|
||||
|
||||
import bisq.core.arbitration.Arbitrator;
|
||||
import bisq.core.util.BSFormatter;
|
||||
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class ArbitratorListItem {
|
||||
public final Arbitrator arbitrator;
|
||||
private final BSFormatter formatter;
|
||||
private final BooleanProperty isSelected = new SimpleBooleanProperty();
|
||||
|
||||
public ArbitratorListItem(Arbitrator arbitrator, BSFormatter formatter) {
|
||||
this.arbitrator = arbitrator;
|
||||
this.formatter = formatter;
|
||||
}
|
||||
|
||||
public String getAddressString() {
|
||||
return arbitrator != null ? arbitrator.getNodeAddress().getFullAddress() : "";
|
||||
}
|
||||
|
||||
public String getLanguageCodes() {
|
||||
return arbitrator != null && arbitrator.getLanguageCodes() != null ?
|
||||
formatter.languageCodesToString(arbitrator.getLanguageCodes()) : "";
|
||||
}
|
||||
|
||||
public String getRegistrationDate() {
|
||||
return arbitrator != null ? formatter.formatDate(new Date(arbitrator.getRegistrationDate())) : "";
|
||||
}
|
||||
|
||||
public boolean getIsSelected() {
|
||||
return isSelected.get();
|
||||
}
|
||||
|
||||
public BooleanProperty isSelectedProperty() {
|
||||
return isSelected;
|
||||
}
|
||||
|
||||
public void setIsSelected(boolean isSelected) {
|
||||
this.isSelected.set(isSelected);
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
~ 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/>.
|
||||
-->
|
||||
|
||||
<?import javafx.scene.layout.AnchorPane?>
|
||||
<?import javafx.scene.layout.ColumnConstraints?>
|
||||
<?import javafx.scene.layout.GridPane?>
|
||||
<GridPane fx:id="root" fx:controller="bisq.desktop.main.account.content.arbitratorselection.ArbitratorSelectionView"
|
||||
hgap="5.0" vgap="5.0"
|
||||
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="20.0"
|
||||
AnchorPane.rightAnchor="25.0" AnchorPane.topAnchor="20.0"
|
||||
xmlns:fx="http://javafx.com/fxml">
|
||||
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" halignment="RIGHT" minWidth="140.0"/>
|
||||
<ColumnConstraints hgrow="ALWAYS" minWidth="300.0"/>
|
||||
</columnConstraints>
|
||||
|
||||
</GridPane>
|
|
@ -1,359 +0,0 @@
|
|||
/*
|
||||
* 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.desktop.main.account.content.arbitratorselection;
|
||||
|
||||
import bisq.desktop.common.view.ActivatableViewAndModel;
|
||||
import bisq.desktop.common.view.FxmlView;
|
||||
import bisq.desktop.components.AutoTooltipButton;
|
||||
import bisq.desktop.components.AutoTooltipCheckBox;
|
||||
import bisq.desktop.components.AutoTooltipLabel;
|
||||
import bisq.desktop.components.AutoTooltipTableColumn;
|
||||
import bisq.desktop.components.TableGroupHeadline;
|
||||
import bisq.desktop.main.overlays.popups.Popup;
|
||||
import bisq.desktop.util.FormBuilder;
|
||||
import bisq.desktop.util.ImageUtil;
|
||||
import bisq.desktop.util.Layout;
|
||||
|
||||
import bisq.core.locale.LanguageUtil;
|
||||
import bisq.core.locale.Res;
|
||||
|
||||
import bisq.common.UserThread;
|
||||
import bisq.common.util.Tuple2;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ListCell;
|
||||
import javafx.scene.control.ListView;
|
||||
import javafx.scene.control.TableCell;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableRow;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.layout.GridPane;
|
||||
|
||||
import javafx.geometry.HPos;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.VPos;
|
||||
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
|
||||
import javafx.collections.ListChangeListener;
|
||||
|
||||
import javafx.util.Callback;
|
||||
import javafx.util.StringConverter;
|
||||
|
||||
import static bisq.desktop.util.FormBuilder.addCheckBox;
|
||||
import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
|
||||
|
||||
@FxmlView
|
||||
public class ArbitratorSelectionView extends ActivatableViewAndModel<GridPane, ArbitratorSelectionViewModel> {
|
||||
|
||||
private final ArbitratorSelectionViewModel model;
|
||||
|
||||
private ListView<String> languagesListView;
|
||||
private ComboBox<String> languageComboBox;
|
||||
private TableView<ArbitratorListItem> tableView;
|
||||
private int gridRow = 0;
|
||||
private CheckBox autoSelectAllMatchingCheckBox;
|
||||
private ListChangeListener<String> listChangeListener;
|
||||
private ListChangeListener<String> languageCodesListChangeListener;
|
||||
private ChangeListener<Boolean> isSelectedChangeListener;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor, lifecycle
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
private ArbitratorSelectionView(ArbitratorSelectionViewModel model) {
|
||||
super(model);
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
addLanguageGroup();
|
||||
addArbitratorsGroup();
|
||||
listChangeListener = c -> languagesListView.setPrefHeight(languagesListView.getItems().size() * Layout.LIST_ROW_HEIGHT + 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
languagesListView.getItems().addListener(listChangeListener);
|
||||
languageComboBox.setItems(model.allLanguageCodes);
|
||||
languagesListView.setItems(model.languageCodes);
|
||||
languagesListView.setPrefHeight(languagesListView.getItems().size() * Layout.LIST_ROW_HEIGHT + 2);
|
||||
|
||||
tableView.setItems(model.arbitratorListItems);
|
||||
// TODO should scale with stage resize
|
||||
tableView.setPrefHeight(200);
|
||||
|
||||
autoSelectAllMatchingCheckBox.setSelected(model.getAutoSelectArbitrators());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
languagesListView.getItems().removeListener(listChangeListener);
|
||||
if (languageCodesListChangeListener != null)
|
||||
model.languageCodes.removeListener(languageCodesListChangeListener);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// UI actions
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void onAddLanguage() {
|
||||
model.onAddLanguage(languageComboBox.getSelectionModel().getSelectedItem());
|
||||
UserThread.execute(() -> languageComboBox.getSelectionModel().clearSelection());
|
||||
}
|
||||
|
||||
private void onRemoveLanguage(String locale) {
|
||||
model.onRemoveLanguage(locale);
|
||||
|
||||
if (languagesListView.getItems().size() == 0) {
|
||||
new Popup<>().warning(Res.get("account.arbitratorSelection.minOneArbitratorRequired")).show();
|
||||
model.onAddLanguage(LanguageUtil.getDefaultLanguageLocaleAsCode());
|
||||
}
|
||||
}
|
||||
|
||||
private void onAddArbitrator(ArbitratorListItem arbitratorListItem) {
|
||||
model.onAddArbitrator(arbitratorListItem.arbitrator);
|
||||
}
|
||||
|
||||
private void onRemoveArbitrator(ArbitratorListItem arbitratorListItem) {
|
||||
model.onRemoveArbitrator(arbitratorListItem.arbitrator);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// UI builder
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void addLanguageGroup() {
|
||||
addTitledGroupBg(root, gridRow, 1, Res.get("account.arbitratorSelection.whichLanguages"));
|
||||
|
||||
Tuple2<Label, ListView<String>> tuple = FormBuilder.addLabelListView(root, gridRow, Res.get("shared.yourLanguage"), Layout.FIRST_ROW_DISTANCE);
|
||||
GridPane.setValignment(tuple.first, VPos.TOP);
|
||||
languagesListView = tuple.second;
|
||||
languagesListView.setMinHeight(3 * Layout.LIST_ROW_HEIGHT + 2);
|
||||
languagesListView.setMaxHeight(6 * Layout.LIST_ROW_HEIGHT + 2);
|
||||
languagesListView.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
|
||||
@Override
|
||||
public ListCell<String> call(ListView<String> list) {
|
||||
return new ListCell<String>() {
|
||||
final Label label = new AutoTooltipLabel();
|
||||
final ImageView icon = ImageUtil.getImageViewById(ImageUtil.REMOVE_ICON);
|
||||
final Button removeButton = new AutoTooltipButton("", icon);
|
||||
final AnchorPane pane = new AnchorPane(label, removeButton);
|
||||
|
||||
{
|
||||
label.setLayoutY(5);
|
||||
removeButton.setId("icon-button");
|
||||
AnchorPane.setRightAnchor(removeButton, 0d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateItem(final String item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null && !empty) {
|
||||
label.setText(LanguageUtil.getDisplayName(item));
|
||||
removeButton.setOnAction(e -> onRemoveLanguage(item));
|
||||
setGraphic(pane);
|
||||
} else {
|
||||
setGraphic(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
languageComboBox = FormBuilder.<String>addLabelComboBox(root, ++gridRow, "", 15).second;
|
||||
languageComboBox.setPromptText(Res.get("shared.addLanguage"));
|
||||
languageComboBox.setButtonCell(new ListCell<String>() {
|
||||
@Override
|
||||
protected void updateItem(final String item, boolean empty) {
|
||||
super.updateItem(item, empty) ;
|
||||
if (empty || item == null) {
|
||||
setText(Res.get("shared.addLanguage"));
|
||||
} else {
|
||||
setText(LanguageUtil.getDisplayName(item));
|
||||
}
|
||||
}
|
||||
});
|
||||
languageComboBox.setConverter(new StringConverter<String>() {
|
||||
@Override
|
||||
public String toString(String code) {
|
||||
return LanguageUtil.getDisplayName(code);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String fromString(String s) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
languageComboBox.setOnHiding(e -> onAddLanguage());
|
||||
}
|
||||
|
||||
private void addArbitratorsGroup() {
|
||||
TableGroupHeadline tableGroupHeadline = new TableGroupHeadline(Res.get("account.arbitratorSelection.whichDoYouAccept"));
|
||||
GridPane.setRowIndex(tableGroupHeadline, ++gridRow);
|
||||
GridPane.setColumnSpan(tableGroupHeadline, 2);
|
||||
GridPane.setMargin(tableGroupHeadline, new Insets(40, -10, -10, -10));
|
||||
root.getChildren().add(tableGroupHeadline);
|
||||
|
||||
tableView = new TableView<>();
|
||||
GridPane.setRowIndex(tableView, gridRow);
|
||||
GridPane.setColumnSpan(tableView, 2);
|
||||
GridPane.setMargin(tableView, new Insets(60, -10, 5, -10));
|
||||
root.getChildren().add(tableView);
|
||||
|
||||
autoSelectAllMatchingCheckBox = addCheckBox(root, ++gridRow, Res.get("account.arbitratorSelection.autoSelect"));
|
||||
GridPane.setColumnSpan(autoSelectAllMatchingCheckBox, 2);
|
||||
GridPane.setHalignment(autoSelectAllMatchingCheckBox, HPos.LEFT);
|
||||
GridPane.setColumnIndex(autoSelectAllMatchingCheckBox, 0);
|
||||
GridPane.setMargin(autoSelectAllMatchingCheckBox, new Insets(0, -10, 0, -10));
|
||||
autoSelectAllMatchingCheckBox.setOnAction(event ->
|
||||
model.setAutoSelectArbitrators(autoSelectAllMatchingCheckBox.isSelected()));
|
||||
|
||||
TableColumn<ArbitratorListItem, String> dateColumn = new AutoTooltipTableColumn<>(Res.get("account.arbitratorSelection.regDate"));
|
||||
dateColumn.setSortable(false);
|
||||
dateColumn.setCellValueFactory(param -> new ReadOnlyObjectWrapper<>(param.getValue().getRegistrationDate()));
|
||||
dateColumn.setMinWidth(140);
|
||||
dateColumn.setMaxWidth(140);
|
||||
|
||||
TableColumn<ArbitratorListItem, String> nameColumn = new AutoTooltipTableColumn<>(Res.get("shared.onionAddress"));
|
||||
nameColumn.setSortable(false);
|
||||
nameColumn.setCellValueFactory(param -> new ReadOnlyObjectWrapper<>(param.getValue().getAddressString()));
|
||||
nameColumn.setMinWidth(90);
|
||||
|
||||
TableColumn<ArbitratorListItem, String> languagesColumn = new AutoTooltipTableColumn<>(Res.get("account.arbitratorSelection.languages"));
|
||||
languagesColumn.setSortable(false);
|
||||
languagesColumn.setCellValueFactory(param -> new ReadOnlyObjectWrapper<>(param.getValue().getLanguageCodes()));
|
||||
languagesColumn.setMinWidth(130);
|
||||
|
||||
TableColumn<ArbitratorListItem, ArbitratorListItem> selectionColumn = new AutoTooltipTableColumn<ArbitratorListItem, ArbitratorListItem>(
|
||||
Res.get("shared.accept")) {
|
||||
{
|
||||
setMinWidth(60);
|
||||
setMaxWidth(60);
|
||||
setSortable(false);
|
||||
}
|
||||
};
|
||||
selectionColumn.setCellValueFactory((arbitrator) -> new ReadOnlyObjectWrapper<>(arbitrator.getValue()));
|
||||
selectionColumn.setCellFactory(
|
||||
new Callback<TableColumn<ArbitratorListItem, ArbitratorListItem>, TableCell<ArbitratorListItem, ArbitratorListItem>>() {
|
||||
@Override
|
||||
public TableCell<ArbitratorListItem, ArbitratorListItem> call(TableColumn<ArbitratorListItem, ArbitratorListItem> column) {
|
||||
return new TableCell<ArbitratorListItem, ArbitratorListItem>() {
|
||||
private final CheckBox checkBox = new AutoTooltipCheckBox();
|
||||
private TableRow tableRow;
|
||||
private BooleanProperty selectedProperty;
|
||||
|
||||
private void updateDisableState(final ArbitratorListItem item) {
|
||||
boolean selected = model.isAcceptedArbitrator(item.arbitrator);
|
||||
item.setIsSelected(selected);
|
||||
|
||||
boolean hasMatchingLanguage = model.hasMatchingLanguage(item.arbitrator);
|
||||
if (!hasMatchingLanguage) {
|
||||
model.onRemoveArbitrator(item.arbitrator);
|
||||
if (selected)
|
||||
item.setIsSelected(false);
|
||||
}
|
||||
|
||||
boolean isMyOwnRegisteredArbitrator = model.isMyOwnRegisteredArbitrator(item.arbitrator);
|
||||
checkBox.setDisable(!hasMatchingLanguage || isMyOwnRegisteredArbitrator);
|
||||
|
||||
tableRow = getTableRow();
|
||||
if (tableRow != null) {
|
||||
tableRow.setOpacity(hasMatchingLanguage && !isMyOwnRegisteredArbitrator ? 1 : 0.4);
|
||||
|
||||
if (isMyOwnRegisteredArbitrator) {
|
||||
String text = Res.get("account.arbitratorSelection.cannotSelectHimself");
|
||||
tableRow.setTooltip(new Tooltip(text));
|
||||
tableRow.setOnMouseClicked(e -> new Popup<>().warning(
|
||||
text).show());
|
||||
} else if (!hasMatchingLanguage) {
|
||||
tableRow.setTooltip(new Tooltip(Res.get("account.arbitratorSelection.noMatchingLang")));
|
||||
tableRow.setOnMouseClicked(e -> new Popup<>()
|
||||
.warning(Res.get("account.arbitratorSelection.noLang")).show());
|
||||
} else {
|
||||
tableRow.setOnMouseClicked(null);
|
||||
tableRow.setTooltip(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateItem(final ArbitratorListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
|
||||
if (item != null && !empty) {
|
||||
selectedProperty = item.isSelectedProperty();
|
||||
languageCodesListChangeListener = c -> updateDisableState(item);
|
||||
model.languageCodes.addListener(languageCodesListChangeListener);
|
||||
|
||||
isSelectedChangeListener = (observable, oldValue, newValue) -> checkBox.setSelected(newValue);
|
||||
selectedProperty.addListener(isSelectedChangeListener);
|
||||
|
||||
checkBox.setSelected(model.isAcceptedArbitrator(item.arbitrator));
|
||||
checkBox.setOnAction(e -> {
|
||||
if (checkBox.isSelected()) {
|
||||
onAddArbitrator(item);
|
||||
} else if (model.isDeselectAllowed(item)) {
|
||||
onRemoveArbitrator(item);
|
||||
} else {
|
||||
new Popup<>().warning(Res.get("account.arbitratorSelection.minOne")).show();
|
||||
checkBox.setSelected(true);
|
||||
}
|
||||
item.setIsSelected(checkBox.isSelected());
|
||||
}
|
||||
);
|
||||
|
||||
updateDisableState(item);
|
||||
setGraphic(checkBox);
|
||||
} else {
|
||||
model.languageCodes.removeListener(languageCodesListChangeListener);
|
||||
if (selectedProperty != null)
|
||||
selectedProperty.removeListener(isSelectedChangeListener);
|
||||
|
||||
setGraphic(null);
|
||||
|
||||
checkBox.setOnAction(null);
|
||||
if (tableRow != null)
|
||||
tableRow.setOnMouseClicked(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
//noinspection unchecked
|
||||
tableView.getColumns().addAll(dateColumn, nameColumn, languagesColumn, selectionColumn);
|
||||
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,175 +0,0 @@
|
|||
/*
|
||||
* 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.desktop.main.account.content.arbitratorselection;
|
||||
|
||||
import bisq.desktop.common.model.ActivatableDataModel;
|
||||
|
||||
import bisq.core.arbitration.Arbitrator;
|
||||
import bisq.core.arbitration.ArbitratorManager;
|
||||
import bisq.core.locale.LanguageUtil;
|
||||
import bisq.core.user.Preferences;
|
||||
import bisq.core.user.User;
|
||||
import bisq.core.util.BSFormatter;
|
||||
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
|
||||
import bisq.common.crypto.KeyRing;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.MapChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
class ArbitratorSelectionViewModel extends ActivatableDataModel {
|
||||
private final User user;
|
||||
private final ArbitratorManager arbitratorManager;
|
||||
private final Preferences preferences;
|
||||
private final KeyRing keyRing;
|
||||
private final BSFormatter formatter;
|
||||
final ObservableList<String> languageCodes = FXCollections.observableArrayList();
|
||||
final ObservableList<ArbitratorListItem> arbitratorListItems = FXCollections.observableArrayList();
|
||||
final ObservableList<String> allLanguageCodes = FXCollections.observableArrayList(LanguageUtil.getAllLanguageCodes());
|
||||
private final MapChangeListener<NodeAddress, Arbitrator> arbitratorMapChangeListener;
|
||||
|
||||
@Inject
|
||||
public ArbitratorSelectionViewModel(User user, ArbitratorManager arbitratorManager, Preferences preferences,
|
||||
KeyRing keyRing, BSFormatter formatter) {
|
||||
this.user = user;
|
||||
this.arbitratorManager = arbitratorManager;
|
||||
this.preferences = preferences;
|
||||
this.keyRing = keyRing;
|
||||
this.formatter = formatter;
|
||||
|
||||
arbitratorMapChangeListener = change -> applyArbitratorMap();
|
||||
}
|
||||
|
||||
private void applyArbitratorMap() {
|
||||
arbitratorListItems.clear();
|
||||
arbitratorListItems.addAll(arbitratorManager.getArbitratorsObservableMap().values().stream()
|
||||
.map(e -> new ArbitratorListItem(e, formatter)).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
languageCodes.setAll(user.getAcceptedLanguageLocaleCodes());
|
||||
arbitratorManager.getArbitratorsObservableMap().addListener(arbitratorMapChangeListener);
|
||||
arbitratorManager.updateArbitratorMap();
|
||||
applyArbitratorMap();
|
||||
|
||||
updateAutoSelectArbitrators();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
arbitratorManager.getArbitratorsObservableMap().removeListener(arbitratorMapChangeListener);
|
||||
}
|
||||
|
||||
void onAddLanguage(String code) {
|
||||
if (code != null) {
|
||||
boolean changed = user.addAcceptedLanguageLocale(code);
|
||||
if (changed)
|
||||
languageCodes.add(code);
|
||||
}
|
||||
|
||||
updateAutoSelectArbitrators();
|
||||
}
|
||||
|
||||
void onRemoveLanguage(String code) {
|
||||
if (code != null) {
|
||||
boolean changed = user.removeAcceptedLanguageLocale(code);
|
||||
if (changed)
|
||||
languageCodes.remove(code);
|
||||
}
|
||||
|
||||
updateAutoSelectArbitrators();
|
||||
}
|
||||
|
||||
void onAddArbitrator(Arbitrator arbitrator) {
|
||||
if (!arbitratorIsTrader(arbitrator)) {
|
||||
user.addAcceptedArbitrator(arbitrator);
|
||||
|
||||
// TODO we mirror arbitrator data for mediator as long we have not impl. it in the UI
|
||||
user.addAcceptedMediator(ArbitratorManager.getMediator(arbitrator));
|
||||
}
|
||||
}
|
||||
|
||||
void onRemoveArbitrator(Arbitrator arbitrator) {
|
||||
if (arbitrator != null) {
|
||||
user.removeAcceptedArbitrator(arbitrator);
|
||||
|
||||
// TODO we mirror arbitrator data for mediator as long we have not impl. it in the UI
|
||||
user.removeAcceptedMediator(ArbitratorManager.getMediator(arbitrator));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDeselectAllowed(ArbitratorListItem arbitratorListItem) {
|
||||
return arbitratorListItem != null
|
||||
&& user.getAcceptedArbitrators() != null
|
||||
&& user.getAcceptedArbitrators().size() > 1;
|
||||
}
|
||||
|
||||
public boolean isAcceptedArbitrator(Arbitrator arbitrator) {
|
||||
return arbitrator != null &&
|
||||
user.getAcceptedArbitrators() != null &&
|
||||
user.getAcceptedArbitrators().contains(arbitrator) &&
|
||||
!isMyOwnRegisteredArbitrator(arbitrator);
|
||||
}
|
||||
|
||||
public boolean arbitratorIsTrader(Arbitrator arbitrator) {
|
||||
return keyRing.getPubKeyRing().equals(arbitrator.getPubKeyRing());
|
||||
}
|
||||
|
||||
public boolean hasMatchingLanguage(Arbitrator arbitrator) {
|
||||
return user.hasMatchingLanguage(arbitrator);
|
||||
}
|
||||
|
||||
public boolean isMyOwnRegisteredArbitrator(Arbitrator arbitrator) {
|
||||
return user.isMyOwnRegisteredArbitrator(arbitrator);
|
||||
}
|
||||
|
||||
private void updateAutoSelectArbitrators() {
|
||||
if (preferences.isAutoSelectArbitrators()) {
|
||||
arbitratorListItems.stream().forEach(item -> {
|
||||
Arbitrator arbitrator = item.arbitrator;
|
||||
if (!isMyOwnRegisteredArbitrator(arbitrator)) {
|
||||
if (hasMatchingLanguage(arbitrator)) {
|
||||
onAddArbitrator(arbitrator);
|
||||
item.setIsSelected(true);
|
||||
} else {
|
||||
onRemoveArbitrator(arbitrator);
|
||||
item.setIsSelected(false);
|
||||
}
|
||||
} else {
|
||||
item.setIsSelected(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void setAutoSelectArbitrators(boolean doAutoSelect) {
|
||||
preferences.setAutoSelectArbitrators(doAutoSelect);
|
||||
updateAutoSelectArbitrators();
|
||||
}
|
||||
|
||||
public boolean getAutoSelectArbitrators() {
|
||||
return preferences.isAutoSelectArbitrators();
|
||||
}
|
||||
}
|
|
@ -28,7 +28,6 @@ import bisq.desktop.components.AutoTooltipToggleButton;
|
|||
import bisq.desktop.main.MainView;
|
||||
import bisq.desktop.main.account.AccountView;
|
||||
import bisq.desktop.main.account.content.altcoinaccounts.AltCoinAccountsView;
|
||||
import bisq.desktop.main.account.content.arbitratorselection.ArbitratorSelectionView;
|
||||
import bisq.desktop.main.account.content.backup.BackupView;
|
||||
import bisq.desktop.main.account.content.fiataccounts.FiatAccountsView;
|
||||
import bisq.desktop.main.account.content.notifications.MobileNotificationsView;
|
||||
|
@ -64,7 +63,7 @@ public class AccountSettingsView extends ActivatableViewAndModel {
|
|||
private final Navigation navigation;
|
||||
|
||||
|
||||
private MenuItem paymentAccount, altCoinsAccountView, arbitratorSelection, notifications, password, seedWords, backup;
|
||||
private MenuItem paymentAccount, altCoinsAccountView, notifications, password, seedWords, backup;
|
||||
private Navigation.Listener listener;
|
||||
|
||||
@FXML
|
||||
|
@ -95,21 +94,18 @@ public class AccountSettingsView extends ActivatableViewAndModel {
|
|||
ToggleGroup toggleGroup = new ToggleGroup();
|
||||
paymentAccount = new MenuItem(navigation, toggleGroup, Res.get("account.menu.paymentAccount"), FiatAccountsView.class, AwesomeIcon.MONEY);
|
||||
altCoinsAccountView = new MenuItem(navigation, toggleGroup, Res.get("account.menu.altCoinsAccountView"), AltCoinAccountsView.class, AwesomeIcon.LINK);
|
||||
arbitratorSelection = new MenuItem(navigation, toggleGroup, Res.get("account.menu.arbitratorSelection"),
|
||||
ArbitratorSelectionView.class, AwesomeIcon.USER_MD);
|
||||
notifications = new MenuItem(navigation, toggleGroup, Res.get("account.menu.notifications"), MobileNotificationsView.class, AwesomeIcon.BELL);
|
||||
password = new MenuItem(navigation, toggleGroup, Res.get("account.menu.password"), PasswordView.class, AwesomeIcon.UNLOCK_ALT);
|
||||
seedWords = new MenuItem(navigation, toggleGroup, Res.get("account.menu.seedWords"), SeedWordsView.class, AwesomeIcon.KEY);
|
||||
backup = new MenuItem(navigation, toggleGroup, Res.get("account.menu.backup"), BackupView.class, AwesomeIcon.CLOUD_DOWNLOAD);
|
||||
|
||||
leftVBox.getChildren().addAll(paymentAccount, altCoinsAccountView, arbitratorSelection, notifications, password, seedWords, backup);
|
||||
leftVBox.getChildren().addAll(paymentAccount, altCoinsAccountView, notifications, password, seedWords, backup);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
paymentAccount.activate();
|
||||
altCoinsAccountView.activate();
|
||||
arbitratorSelection.activate();
|
||||
notifications.activate();
|
||||
password.activate();
|
||||
seedWords.activate();
|
||||
|
@ -135,7 +131,6 @@ public class AccountSettingsView extends ActivatableViewAndModel {
|
|||
|
||||
paymentAccount.deactivate();
|
||||
altCoinsAccountView.deactivate();
|
||||
arbitratorSelection.deactivate();
|
||||
notifications.deactivate();
|
||||
password.deactivate();
|
||||
seedWords.deactivate();
|
||||
|
@ -148,7 +143,6 @@ public class AccountSettingsView extends ActivatableViewAndModel {
|
|||
|
||||
if (view instanceof FiatAccountsView) paymentAccount.setSelected(true);
|
||||
else if (view instanceof AltCoinAccountsView) altCoinsAccountView.setSelected(true);
|
||||
else if (view instanceof ArbitratorSelectionView) arbitratorSelection.setSelected(true);
|
||||
else if (view instanceof MobileNotificationsView) notifications.setSelected(true);
|
||||
else if (view instanceof PasswordView) password.setSelected(true);
|
||||
else if (view instanceof SeedWordsView) seedWords.setSelected(true);
|
||||
|
|
|
@ -40,7 +40,6 @@ import bisq.core.trade.protocol.tasks.maker.MakerProcessDepositTxPublishedMessag
|
|||
import bisq.core.trade.protocol.tasks.maker.MakerProcessPayDepositRequest;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerSendPublishDepositTxRequest;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerSetupDepositTxListener;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerVerifyArbitratorSelection;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerVerifyMediatorSelection;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerVerifyTakerAccount;
|
||||
import bisq.core.trade.protocol.tasks.maker.MakerVerifyTakerFeePayment;
|
||||
|
@ -108,7 +107,6 @@ public class DebugView extends InitializableView<GridPane, Void> {
|
|||
FXCollections.observableArrayList(Arrays.asList(
|
||||
MakerProcessPayDepositRequest.class,
|
||||
CheckIfPeerIsBanned.class,
|
||||
MakerVerifyArbitratorSelection.class,
|
||||
MakerVerifyMediatorSelection.class,
|
||||
MakerVerifyTakerAccount.class,
|
||||
MakerVerifyTakerFeePayment.class,
|
||||
|
@ -187,7 +185,6 @@ public class DebugView extends InitializableView<GridPane, Void> {
|
|||
FXCollections.observableArrayList(Arrays.asList(
|
||||
MakerProcessPayDepositRequest.class,
|
||||
CheckIfPeerIsBanned.class,
|
||||
MakerVerifyArbitratorSelection.class,
|
||||
MakerVerifyMediatorSelection.class,
|
||||
MakerVerifyTakerAccount.class,
|
||||
MakerVerifyTakerFeePayment.class,
|
||||
|
|
|
@ -30,7 +30,6 @@ import bisq.desktop.components.InputTextField;
|
|||
import bisq.desktop.components.TitledGroupBg;
|
||||
import bisq.desktop.main.MainView;
|
||||
import bisq.desktop.main.account.AccountView;
|
||||
import bisq.desktop.main.account.content.arbitratorselection.ArbitratorSelectionView;
|
||||
import bisq.desktop.main.account.content.fiataccounts.FiatAccountsView;
|
||||
import bisq.desktop.main.account.settings.AccountSettingsView;
|
||||
import bisq.desktop.main.dao.DaoView;
|
||||
|
@ -352,13 +351,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel> extends
|
|||
});
|
||||
}
|
||||
} else {
|
||||
new Popup<>().headLine(Res.get("popup.warning.noArbitratorSelected.headline"))
|
||||
.instruction(Res.get("popup.warning.noArbitratorSelected.msg"))
|
||||
.actionButtonTextWithGoTo("navigation.arbitratorSelection")
|
||||
.onAction(() -> {
|
||||
navigation.setReturnPath(navigation.getCurrentPath());
|
||||
navigation.navigateTo(MainView.class, AccountView.class, AccountSettingsView.class, ArbitratorSelectionView.class);
|
||||
}).show();
|
||||
new Popup<>().warning(Res.get("popup.warning.noArbitratorsAvailable")).show();
|
||||
}
|
||||
} else {
|
||||
showInsufficientBsqFundsForBtcFeePaymentPopup();
|
||||
|
@ -728,9 +721,9 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel> extends
|
|||
};
|
||||
|
||||
volumeListener = (observable, oldValue, newValue) -> {
|
||||
if (!newValue.equals("") && CurrencyUtil.isFiatCurrency(model.tradeCurrencyCode.get())) {
|
||||
volumeInfoInputTextField.setContentForPrivacyPopOver(createPopoverLabel(Res.get("offerbook.info.roundedFiatVolume")));
|
||||
}
|
||||
if (!newValue.equals("") && CurrencyUtil.isFiatCurrency(model.tradeCurrencyCode.get())) {
|
||||
volumeInfoInputTextField.setContentForPrivacyPopOver(createPopoverLabel(Res.get("offerbook.info.roundedFiatVolume")));
|
||||
}
|
||||
};
|
||||
|
||||
marketPriceMarginListener = (observable, oldValue, newValue) -> {
|
||||
|
|
|
@ -29,7 +29,6 @@ import bisq.desktop.components.InfoAutoTooltipLabel;
|
|||
import bisq.desktop.components.PeerInfoIcon;
|
||||
import bisq.desktop.main.MainView;
|
||||
import bisq.desktop.main.account.AccountView;
|
||||
import bisq.desktop.main.account.content.arbitratorselection.ArbitratorSelectionView;
|
||||
import bisq.desktop.main.account.content.fiataccounts.FiatAccountsView;
|
||||
import bisq.desktop.main.account.settings.AccountSettingsView;
|
||||
import bisq.desktop.main.funds.FundsView;
|
||||
|
@ -409,10 +408,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
})
|
||||
.show();
|
||||
} else if (!model.hasAcceptedArbitrators()) {
|
||||
openPopupForMissingAccountSetup(Res.get("popup.warning.noArbitratorSelected.headline"),
|
||||
Res.get("popup.warning.noArbitratorSelected.msg"),
|
||||
ArbitratorSelectionView.class,
|
||||
"navigation.arbitratorSelection");
|
||||
new Popup<>().warning(Res.get("popup.warning.noArbitratorsAvailable")).show();
|
||||
} else {
|
||||
createOfferButton.setDisable(true);
|
||||
offerActionHandler.onCreateOffer(model.getSelectedTradeCurrency());
|
||||
|
@ -421,7 +417,6 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
|
||||
private void onShowInfo(Offer offer,
|
||||
boolean isPaymentAccountValidForOffer,
|
||||
boolean hasMatchingArbitrator,
|
||||
boolean hasSameProtocolVersion,
|
||||
boolean isIgnored,
|
||||
boolean isOfferBanned,
|
||||
|
@ -429,12 +424,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
boolean isPaymentMethodBanned,
|
||||
boolean isNodeAddressBanned,
|
||||
boolean isInsufficientTradeLimit) {
|
||||
if (!hasMatchingArbitrator) {
|
||||
openPopupForMissingAccountSetup(Res.get("popup.warning.noArbitratorSelected.headline"),
|
||||
Res.get("popup.warning.noArbitratorSelected.msg"),
|
||||
ArbitratorSelectionView.class,
|
||||
"navigation.arbitratorSelection");
|
||||
} else if (!isPaymentAccountValidForOffer) {
|
||||
if (!isPaymentAccountValidForOffer) {
|
||||
openPopupForMissingAccountSetup(Res.get("offerbook.warning.noMatchingAccount.headline"),
|
||||
Res.get("offerbook.warning.noMatchingAccount.msg"),
|
||||
FiatAccountsView.class,
|
||||
|
@ -804,7 +794,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
return new TableCell<OfferBookListItem, OfferBookListItem>() {
|
||||
final ImageView iconView = new ImageView();
|
||||
final Button button = new AutoTooltipButton();
|
||||
boolean isTradable, isPaymentAccountValidForOffer, hasMatchingArbitrator,
|
||||
boolean isTradable, isPaymentAccountValidForOffer,
|
||||
hasSameProtocolVersion, isIgnored, isOfferBanned, isCurrencyBanned,
|
||||
isPaymentMethodBanned, isNodeAddressBanned, isInsufficientTradeLimit;
|
||||
|
||||
|
@ -825,7 +815,6 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
boolean myOffer = model.isMyOffer(offer);
|
||||
if (tableRow != null) {
|
||||
isPaymentAccountValidForOffer = model.isAnyPaymentAccountValidForOffer(offer);
|
||||
hasMatchingArbitrator = model.hasMatchingArbitrator(offer);
|
||||
hasSameProtocolVersion = model.hasSameProtocolVersion(offer);
|
||||
isIgnored = model.isIgnored(offer);
|
||||
isOfferBanned = model.isOfferBanned(offer);
|
||||
|
@ -834,7 +823,6 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
isNodeAddressBanned = model.isNodeAddressBanned(offer);
|
||||
isInsufficientTradeLimit = model.isInsufficientTradeLimit(offer);
|
||||
isTradable = isPaymentAccountValidForOffer &&
|
||||
hasMatchingArbitrator &&
|
||||
hasSameProtocolVersion &&
|
||||
!isIgnored &&
|
||||
!isOfferBanned &&
|
||||
|
@ -856,7 +844,6 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
if (!(e.getTarget() instanceof ImageView || e.getTarget() instanceof Canvas))
|
||||
onShowInfo(offer,
|
||||
isPaymentAccountValidForOffer,
|
||||
hasMatchingArbitrator,
|
||||
hasSameProtocolVersion,
|
||||
isIgnored,
|
||||
isOfferBanned,
|
||||
|
@ -888,7 +875,6 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||
if (!myOffer && !isTradable)
|
||||
button.setOnAction(e -> onShowInfo(offer,
|
||||
isPaymentAccountValidForOffer,
|
||||
hasMatchingArbitrator,
|
||||
hasSameProtocolVersion,
|
||||
isIgnored,
|
||||
isOfferBanned,
|
||||
|
|
|
@ -536,19 +536,6 @@ class OfferBookViewModel extends ActivatableViewModel {
|
|||
});
|
||||
}
|
||||
|
||||
boolean hasMatchingArbitrator(Offer offer) {
|
||||
final List<NodeAddress> acceptedArbitratorAddresses = user.getAcceptedArbitratorAddresses();
|
||||
if (acceptedArbitratorAddresses != null) {
|
||||
for (NodeAddress offerArbitratorNodeAddress : offer.getArbitratorNodeAddresses()) {
|
||||
for (NodeAddress acceptedArbitratorNodeAddress : acceptedArbitratorAddresses) {
|
||||
if (offerArbitratorNodeAddress.equals(acceptedArbitratorNodeAddress))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean isIgnored(Offer offer) {
|
||||
return preferences.getIgnoreTradersList().stream()
|
||||
.anyMatch(i -> i.equals(offer.getMakerNodeAddress().getHostNameWithoutPostFix()));
|
||||
|
|
|
@ -30,9 +30,6 @@ import bisq.desktop.components.InfoTextField;
|
|||
import bisq.desktop.components.InputTextField;
|
||||
import bisq.desktop.components.TitledGroupBg;
|
||||
import bisq.desktop.main.MainView;
|
||||
import bisq.desktop.main.account.AccountView;
|
||||
import bisq.desktop.main.account.content.arbitratorselection.ArbitratorSelectionView;
|
||||
import bisq.desktop.main.account.settings.AccountSettingsView;
|
||||
import bisq.desktop.main.dao.DaoView;
|
||||
import bisq.desktop.main.dao.wallet.BsqWalletView;
|
||||
import bisq.desktop.main.dao.wallet.receive.BsqReceiveView;
|
||||
|
@ -393,14 +390,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
|||
});
|
||||
}
|
||||
} else {
|
||||
new Popup<>().headLine(Res.get("popup.warning.noArbitratorSelected.headline"))
|
||||
.instruction(Res.get("popup.warning.noArbitratorSelected.msg"))
|
||||
.actionButtonTextWithGoTo("navigation.arbitratorSelection")
|
||||
.onAction(() -> {
|
||||
navigation.setReturnPath(navigation.getCurrentPath());
|
||||
navigation.navigateTo(MainView.class, AccountView.class, AccountSettingsView.class,
|
||||
ArbitratorSelectionView.class);
|
||||
}).show();
|
||||
new Popup<>().warning(Res.get("popup.warning.noArbitratorsAvailable")).show();
|
||||
}
|
||||
} else {
|
||||
showInsufficientBsqFundsForBtcFeePaymentPopup();
|
||||
|
|
|
@ -19,10 +19,6 @@ package bisq.desktop.main.overlays.windows;
|
|||
|
||||
import bisq.desktop.Navigation;
|
||||
import bisq.desktop.components.BusyAnimation;
|
||||
import bisq.desktop.main.MainView;
|
||||
import bisq.desktop.main.account.AccountView;
|
||||
import bisq.desktop.main.account.content.arbitratorselection.ArbitratorSelectionView;
|
||||
import bisq.desktop.main.account.settings.AccountSettingsView;
|
||||
import bisq.desktop.main.overlays.Overlay;
|
||||
import bisq.desktop.main.overlays.popups.Popup;
|
||||
import bisq.desktop.util.Layout;
|
||||
|
@ -398,9 +394,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
|
|||
takeOfferHandlerOptional.get().run();
|
||||
}
|
||||
} else {
|
||||
new Popup<>().warning(Res.get("offerDetailsWindow.warn.noArbitrator")).show();
|
||||
navigation.navigateTo(MainView.class, AccountView.class, AccountSettingsView.class,
|
||||
ArbitratorSelectionView.class);
|
||||
new Popup<>().warning(Res.get("popup.warning.noArbitratorsAvailable")).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -95,7 +95,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
|||
private ComboBox<TradeCurrency> preferredTradeCurrencyComboBox;
|
||||
private ComboBox<BaseCurrencyNetwork> selectBaseCurrencyNetworkComboBox;
|
||||
|
||||
private CheckBox useAnimationsCheckBox, autoSelectArbitratorsCheckBox, avoidStandbyModeCheckBox,
|
||||
private CheckBox useAnimationsCheckBox, avoidStandbyModeCheckBox,
|
||||
showOwnOffersInOfferBook, sortMarketCurrenciesNumericallyCheckBox, useCustomFeeCheckbox;
|
||||
private int gridRow = 0;
|
||||
private InputTextField transactionFeeInputTextField, ignoreTradersListInputTextField, referralIdInputTextField;
|
||||
|
@ -185,7 +185,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void initializeGeneralOptions() {
|
||||
TitledGroupBg titledGroupBg = addTitledGroupBg(root, gridRow, 10, Res.get("setting.preferences.general"));
|
||||
TitledGroupBg titledGroupBg = addTitledGroupBg(root, gridRow, 9, Res.get("setting.preferences.general"));
|
||||
GridPane.setColumnSpan(titledGroupBg, 4);
|
||||
|
||||
// selectBaseCurrencyNetwork
|
||||
|
@ -287,10 +287,6 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
|||
UserThread.runAfter(() -> deviationInputTextField.setText(formatter.formatPercentagePrice(preferences.getMaxPriceDistanceInPercent())), 100, TimeUnit.MILLISECONDS);
|
||||
};
|
||||
|
||||
// autoSelectArbitrators
|
||||
autoSelectArbitratorsCheckBox = addLabelCheckBox(root, ++gridRow,
|
||||
Res.get("setting.preferences.autoSelectArbitrators"), "").second;
|
||||
|
||||
// ignoreTraders
|
||||
ignoreTradersListInputTextField = addLabelInputTextField(root, ++gridRow,
|
||||
Res.get("setting.preferences.ignorePeers")).second;
|
||||
|
@ -680,9 +676,6 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
|||
|
||||
resetDontShowAgainButton.setOnAction(e -> preferences.resetDontShowAgain());
|
||||
|
||||
autoSelectArbitratorsCheckBox.setSelected(preferences.isAutoSelectArbitrators());
|
||||
autoSelectArbitratorsCheckBox.setOnAction(e -> preferences.setAutoSelectArbitrators(autoSelectArbitratorsCheckBox.isSelected()));
|
||||
|
||||
// We use opposite property (useStandbyMode) in preferences to have the default value (false) set as we want it,
|
||||
// so users who update gets set avoidStandbyMode=true (useStandbyMode=false)
|
||||
avoidStandbyModeCheckBox.setSelected(!preferences.isUseStandbyMode());
|
||||
|
@ -734,7 +727,6 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
|||
// useStickyMarketPriceCheckBox.setOnAction(null);
|
||||
sortMarketCurrenciesNumericallyCheckBox.setOnAction(null);
|
||||
showOwnOffersInOfferBook.setOnAction(null);
|
||||
autoSelectArbitratorsCheckBox.setOnAction(null);
|
||||
resetDontShowAgainButton.setOnAction(null);
|
||||
avoidStandbyModeCheckBox.setOnAction(null);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue