Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for referrer IDs at offers and trades #1590

Merged
merged 1 commit into from
Jun 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/main/java/bisq/desktop/app/BisqApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,6 @@ private MainView loadMainView(Injector injector) {

private void addSceneKeyEventHandler(Scene scene, Injector injector) {
scene.addEventHandler(KeyEvent.KEY_RELEASED, keyEvent -> {
Utilities.isAltOrCtrlPressed(KeyCode.W, keyEvent);
if (Utilities.isCtrlPressed(KeyCode.W, keyEvent) ||
Utilities.isCtrlPressed(KeyCode.Q, keyEvent)) {
stop();
Expand Down
103 changes: 102 additions & 1 deletion src/main/java/bisq/desktop/main/market/MarketView.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,31 +28,62 @@
import bisq.desktop.main.market.offerbook.OfferBookChartView;
import bisq.desktop.main.market.spread.SpreadView;
import bisq.desktop.main.market.trades.TradesChartsView;
import bisq.desktop.main.offer.offerbook.OfferBook;
import bisq.desktop.main.overlays.popups.Popup;
import bisq.desktop.util.BSFormatter;

import bisq.core.locale.Res;
import bisq.core.offer.OfferPayload;
import bisq.core.trade.statistics.TradeStatistics2;

import bisq.network.p2p.P2PService;

import bisq.common.util.Utilities;

import javax.inject.Inject;

import com.google.common.base.Joiner;

import org.apache.commons.lang3.StringUtils;

import javafx.fxml.FXML;

import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;

import javafx.beans.value.ChangeListener;

import javafx.event.EventHandler;

import java.util.List;
import java.util.stream.Collectors;

@FxmlView
public class MarketView extends ActivatableViewAndModel<TabPane, Activatable> {
@FXML
Tab offerBookTab, tradesTab, spreadTab;
private final ViewLoader viewLoader;
private final P2PService p2PService;
private final OfferBook offerBook;
private final BSFormatter formatter;
private final Navigation navigation;
private Navigation.Listener navigationListener;
private ChangeListener<Tab> tabChangeListener;
private EventHandler<KeyEvent> keyEventEventHandler;
private Scene scene;


@Inject
public MarketView(CachingViewLoader viewLoader, Navigation navigation) {
public MarketView(CachingViewLoader viewLoader, P2PService p2PService, OfferBook offerBook, BSFormatter formatter,
Navigation navigation) {
this.viewLoader = viewLoader;
this.p2PService = p2PService;
this.offerBook = offerBook;
this.formatter = formatter;
this.navigation = navigation;
}

Expand All @@ -78,6 +109,22 @@ else if (newValue == spreadTab)
//noinspection unchecked
navigation.navigateTo(MainView.class, MarketView.class, SpreadView.class);
};

keyEventEventHandler = keyEvent -> {
if (Utilities.isCtrlPressed(KeyCode.T, keyEvent)) {
String allTradesWithReferralId = getAllTradesWithReferralId();
new Popup<>().message(StringUtils.abbreviate(allTradesWithReferralId, 600))
.actionButtonText(Res.get("shared.copyToClipboard"))
.onAction(() -> Utilities.copyToClipboard(allTradesWithReferralId))
.show();
} else if (Utilities.isCtrlPressed(KeyCode.O, keyEvent)) {
String allOffersWithReferralId = getAllOffersWithReferralId();
new Popup<>().message(StringUtils.abbreviate(allOffersWithReferralId, 600))
.actionButtonText(Res.get("shared.copyToClipboard"))
.onAction(() -> Utilities.copyToClipboard(allOffersWithReferralId))
.show();
}
};
}

@Override
Expand All @@ -94,12 +141,21 @@ else if (root.getSelectionModel().getSelectedItem() == tradesTab)
else
//noinspection unchecked
navigation.navigateTo(MainView.class, MarketView.class, SpreadView.class);

if (root.getScene() != null) {
scene = root.getScene();
scene.addEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler);
}
}

@Override
protected void deactivate() {
root.getSelectionModel().selectedItemProperty().removeListener(tabChangeListener);
navigation.removeListener(navigationListener);

// root.getScene() is null already so we used a field property
if (scene != null)
scene.removeEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler);
}

private void loadView(Class<? extends View> viewClass) {
Expand All @@ -119,4 +175,49 @@ private void loadView(Class<? extends View> viewClass) {
root.getSelectionModel().select(tab);
}

private String getAllTradesWithReferralId() {
// We don't use the list from the tradeStatisticsManager as that has filtered the duplicates but we want to get
// all items of both traders in case the referral ID was only set by one trader.
// If both traders had set it the tradeStatistics is only delivered once.
// If both traders used a differnet refferral ID then we would get 2 objects.
List<String> list = p2PService.getP2PDataStorage().getPersistableNetworkPayloadList().getMap().values().stream()
.filter(e -> e instanceof TradeStatistics2)
.map(e -> (TradeStatistics2) e)
.filter(tradeStatistics2 -> tradeStatistics2.getExtraDataMap() != null)
.filter(tradeStatistics2 -> tradeStatistics2.getExtraDataMap().get(OfferPayload.REFERRAL_ID) != null)
.map(trade -> {
StringBuilder sb = new StringBuilder();
sb.append("Trade ID: ").append(trade.getOfferId()).append("\n")
.append("Date: ").append(formatter.formatDateTime(trade.getTradeDate())).append("\n")
.append("Market: ").append(formatter.getCurrencyPair(trade.getCurrencyCode())).append("\n")
.append("Price: ").append(formatter.formatPrice(trade.getTradePrice())).append("\n")
.append("Amount: ").append(formatter.formatCoin(trade.getTradeAmount())).append("\n")
.append("Volume: ").append(formatter.formatVolume(trade.getTradeVolume())).append("\n")
.append("Payment method: ").append(Res.get(trade.getOfferPaymentMethod())).append("\n")
.append("ReferralID: ").append(trade.getExtraDataMap().get(OfferPayload.REFERRAL_ID));
return sb.toString();
})
.collect(Collectors.toList());
return Joiner.on("\n\n").join(list);
}

private String getAllOffersWithReferralId() {
List<String> list = offerBook.getOfferBookListItems().stream()
.map(offerBookListItem -> offerBookListItem.getOffer())
.filter(offer -> offer.getOfferPayload().getExtraDataMap() != null)
.filter(offer -> offer.getOfferPayload().getExtraDataMap().get(OfferPayload.REFERRAL_ID) != null)
.map(offer -> {
StringBuilder sb = new StringBuilder();
sb.append("Offer ID: ").append(offer.getId()).append("\n")
.append("Type: ").append(offer.getDirection().name()).append("\n")
.append("Market: ").append(formatter.getCurrencyPair(offer.getCurrencyCode())).append("\n")
.append("Price: ").append(formatter.formatPrice(offer.getPrice())).append("\n")
.append("Amount: ").append(formatter.formatAmount(offer)).append(" BTC\n")
.append("Payment method: ").append(Res.get(offer.getPaymentMethod().getId())).append("\n")
.append("ReferralID: ").append(offer.getOfferPayload().getExtraDataMap().get(OfferPayload.REFERRAL_ID));
return sb.toString();
})
.collect(Collectors.toList());
return Joiner.on("\n\n").join(list);
}
}
14 changes: 12 additions & 2 deletions src/main/java/bisq/desktop/main/offer/EditableOfferDataModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import bisq.core.provider.fee.FeeService;
import bisq.core.provider.price.PriceFeedService;
import bisq.core.trade.handlers.TransactionResultHandler;
import bisq.core.trade.statistics.ReferralIdService;
import bisq.core.user.Preferences;
import bisq.core.user.User;

Expand Down Expand Up @@ -86,6 +87,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;

Expand All @@ -107,6 +109,7 @@ public abstract class EditableOfferDataModel extends OfferDataModel implements B
private final AccountAgeWitnessService accountAgeWitnessService;
private final TradeWalletService tradeWalletService;
private final FeeService feeService;
private final ReferralIdService referralIdService;
private final BSFormatter formatter;
private final String offerId;
private final BalanceListener btcBalanceListener;
Expand Down Expand Up @@ -147,7 +150,7 @@ public EditableOfferDataModel(OpenOfferManager openOfferManager, BtcWalletServic
Preferences preferences, User user, KeyRing keyRing, P2PService p2PService,
PriceFeedService priceFeedService, FilterManager filterManager,
AccountAgeWitnessService accountAgeWitnessService, TradeWalletService tradeWalletService,
FeeService feeService, BSFormatter formatter) {
FeeService feeService, ReferralIdService referralIdService, BSFormatter formatter) {
super(btcWalletService);

this.openOfferManager = openOfferManager;
Expand All @@ -161,6 +164,7 @@ public EditableOfferDataModel(OpenOfferManager openOfferManager, BtcWalletServic
this.accountAgeWitnessService = accountAgeWitnessService;
this.tradeWalletService = tradeWalletService;
this.feeService = feeService;
this.referralIdService = referralIdService;
this.formatter = formatter;

offerId = Utilities.getRandomPrefix(5, 8) + "-" +
Expand Down Expand Up @@ -357,13 +361,19 @@ Offer createAndGetOffer() {
long lowerClosePrice = 0;
long upperClosePrice = 0;
String hashOfChallenge = null;
HashMap<String, String> extraDataMap = null;
Map<String, String> extraDataMap = null;
if (CurrencyUtil.isFiatCurrency(currencyCode)) {
extraDataMap = new HashMap<>();
final String myWitnessHashAsHex = accountAgeWitnessService.getMyWitnessHashAsHex(paymentAccount.getPaymentAccountPayload());
extraDataMap.put(OfferPayload.ACCOUNT_AGE_WITNESS_HASH, myWitnessHashAsHex);
}

if (referralIdService.getOptionalReferralId().isPresent()) {
if (extraDataMap == null)
extraDataMap = new HashMap<>();
extraDataMap.put(OfferPayload.REFERRAL_ID, referralIdService.getOptionalReferralId().get());
}

Coin buyerSecurityDepositAsCoin = buyerSecurityDeposit.get();
checkArgument(buyerSecurityDepositAsCoin.compareTo(Restrictions.getMaxBuyerSecurityDeposit()) <= 0,
"securityDeposit must be not exceed " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.provider.fee.FeeService;
import bisq.core.provider.price.PriceFeedService;
import bisq.core.trade.statistics.ReferralIdService;
import bisq.core.user.Preferences;
import bisq.core.user.User;

Expand All @@ -45,7 +46,7 @@
class CreateOfferDataModel extends EditableOfferDataModel {

@Inject
public CreateOfferDataModel(OpenOfferManager openOfferManager, BtcWalletService btcWalletService, BsqWalletService bsqWalletService, Preferences preferences, User user, KeyRing keyRing, P2PService p2PService, PriceFeedService priceFeedService, FilterManager filterManager, AccountAgeWitnessService accountAgeWitnessService, TradeWalletService tradeWalletService, FeeService feeService, BSFormatter formatter) {
super(openOfferManager, btcWalletService, bsqWalletService, preferences, user, keyRing, p2PService, priceFeedService, filterManager, accountAgeWitnessService, tradeWalletService, feeService, formatter);
public CreateOfferDataModel(OpenOfferManager openOfferManager, BtcWalletService btcWalletService, BsqWalletService bsqWalletService, Preferences preferences, User user, KeyRing keyRing, P2PService p2PService, PriceFeedService priceFeedService, FilterManager filterManager, AccountAgeWitnessService accountAgeWitnessService, TradeWalletService tradeWalletService, FeeService feeService, ReferralIdService referralIdService, BSFormatter formatter) {
super(openOfferManager, btcWalletService, bsqWalletService, preferences, user, keyRing, p2PService, priceFeedService, filterManager, accountAgeWitnessService, tradeWalletService, feeService, referralIdService, formatter);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import bisq.core.payment.PaymentAccount;
import bisq.core.provider.fee.FeeService;
import bisq.core.provider.price.PriceFeedService;
import bisq.core.trade.statistics.ReferralIdService;
import bisq.core.user.Preferences;
import bisq.core.user.User;

Expand All @@ -52,8 +53,8 @@ class EditOpenOfferDataModel extends EditableOfferDataModel {
private OpenOffer.State initialState;

@Inject
EditOpenOfferDataModel(OpenOfferManager openOfferManager, BtcWalletService btcWalletService, BsqWalletService bsqWalletService, Preferences preferences, User user, KeyRing keyRing, P2PService p2PService, PriceFeedService priceFeedService, FilterManager filterManager, AccountAgeWitnessService accountAgeWitnessService, TradeWalletService tradeWalletService, FeeService feeService, BSFormatter formatter) {
super(openOfferManager, btcWalletService, bsqWalletService, preferences, user, keyRing, p2PService, priceFeedService, filterManager, accountAgeWitnessService, tradeWalletService, feeService, formatter);
EditOpenOfferDataModel(OpenOfferManager openOfferManager, BtcWalletService btcWalletService, BsqWalletService bsqWalletService, Preferences preferences, User user, KeyRing keyRing, P2PService p2PService, PriceFeedService priceFeedService, FilterManager filterManager, AccountAgeWitnessService accountAgeWitnessService, TradeWalletService tradeWalletService, FeeService feeService, ReferralIdService referralIdService, BSFormatter formatter) {
super(openOfferManager, btcWalletService, bsqWalletService, preferences, user, keyRing, p2PService, priceFeedService, filterManager, accountAgeWitnessService, tradeWalletService, feeService, referralIdService, formatter);
}

public void initWithData(OpenOffer openOffer) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
import bisq.core.provider.fee.FeeService;
import bisq.core.trade.statistics.ReferralIdService;
import bisq.core.user.BlockChainExplorer;
import bisq.core.user.Preferences;

Expand Down Expand Up @@ -95,11 +96,11 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Activatab

private CheckBox useAnimationsCheckBox, autoSelectArbitratorsCheckBox, showOwnOffersInOfferBook, sortMarketCurrenciesNumericallyCheckBox, useCustomFeeCheckbox;
private int gridRow = 0;
private InputTextField transactionFeeInputTextField, ignoreTradersListInputTextField;
private InputTextField transactionFeeInputTextField, ignoreTradersListInputTextField, referralIdInputTextField;
private ChangeListener<Boolean> transactionFeeFocusedListener;
private final Preferences preferences;
private final FeeService feeService;
private final BisqEnvironment bisqEnvironment;
private final ReferralIdService referralIdService;
private final BSFormatter formatter;

private ListView<FiatCurrency> fiatCurrenciesListView;
Expand All @@ -117,7 +118,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Activatab
private ObservableList<CryptoCurrency> allCryptoCurrencies;
private ObservableList<TradeCurrency> tradeCurrencies;
private InputTextField deviationInputTextField;
private ChangeListener<String> deviationListener, ignoreTradersListListener;
private ChangeListener<String> deviationListener, ignoreTradersListListener, referralIdListener;
private ChangeListener<Boolean> deviationFocusedListener;
private ChangeListener<Boolean> useCustomFeeCheckboxListener;
private ChangeListener<Number> transactionFeeChangeListener;
Expand All @@ -127,12 +128,12 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Activatab
///////////////////////////////////////////////////////////////////////////////////////////

@Inject
public PreferencesView(Preferences preferences, FeeService feeService,
BisqEnvironment bisqEnvironment, BSFormatter formatter) {
public PreferencesView(Preferences preferences, FeeService feeService, ReferralIdService referralIdService,
BSFormatter formatter) {
super();
this.preferences = preferences;
this.feeService = feeService;
this.bisqEnvironment = bisqEnvironment;
this.referralIdService = referralIdService;
this.formatter = formatter;
}

Expand Down Expand Up @@ -176,7 +177,7 @@ protected void deactivate() {
///////////////////////////////////////////////////////////////////////////////////////////

private void initializeGeneralOptions() {
TitledGroupBg titledGroupBg = addTitledGroupBg(root, gridRow, 7, Res.get("setting.preferences.general"));
TitledGroupBg titledGroupBg = addTitledGroupBg(root, gridRow, 8, Res.get("setting.preferences.general"));
GridPane.setColumnSpan(titledGroupBg, 4);

// selectBaseCurrencyNetwork
Expand Down Expand Up @@ -298,6 +299,13 @@ public BaseCurrencyNetwork fromString(String string) {
preferences.setIgnoreTradersList(Arrays.asList(StringUtils.deleteWhitespace(newValue)
.replace(":9999", "").replace(".onion", "")
.split(",")));

// referralId
referralIdInputTextField = addLabelInputTextField(root, ++gridRow, Res.get("setting.preferences.refererId")).second;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this field could get a grayed out text that disappears when focusing saying something like "optional referral code" to make it clear it's just optional and generate less confusion.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think also it would be good to make it clear that it's just optional.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, good point. I also though it might require some extra info. I will add a prompt text when not filled.

referralIdListener = (observable, oldValue, newValue) -> {
if (!newValue.equals(oldValue))
referralIdService.setReferralId(newValue);
};
}

private void initializeDisplayCurrencies() {
Expand Down Expand Up @@ -496,7 +504,7 @@ private void activateGeneralOptions() {

transactionFeeInputTextField.setText(String.valueOf(getTxFeeForWithdrawalPerByte()));
ignoreTradersListInputTextField.setText(preferences.getIgnoreTradersList().stream().collect(Collectors.joining(", ")));

referralIdService.getOptionalReferralId().ifPresent(referralId -> referralIdInputTextField.setText(referralId));
userLanguageComboBox.setItems(languageCodes);
userLanguageComboBox.getSelectionModel().select(preferences.getUserLanguage());
userLanguageComboBox.setConverter(new StringConverter<String>() {
Expand Down Expand Up @@ -574,6 +582,7 @@ public BlockChainExplorer fromString(String string) {
transactionFeeInputTextField.focusedProperty().addListener(transactionFeeFocusedListener);
ignoreTradersListInputTextField.textProperty().addListener(ignoreTradersListListener);
useCustomFeeCheckbox.selectedProperty().addListener(useCustomFeeCheckboxListener);
referralIdInputTextField.textProperty().addListener(referralIdListener);
}

private Coin getTxFeeForWithdrawalPerByte() {
Expand Down Expand Up @@ -678,6 +687,7 @@ private void deactivateGeneralOptions() {
feeService.feeUpdateCounterProperty().removeListener(transactionFeeChangeListener);
ignoreTradersListInputTextField.textProperty().removeListener(ignoreTradersListListener);
useCustomFeeCheckbox.selectedProperty().removeListener(useCustomFeeCheckboxListener);
referralIdInputTextField.textProperty().removeListener(referralIdListener);
}

private void deactivateDisplayCurrencies() {
Expand Down