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

Re-introduce account age to chargeback risk payment methods #3580

Merged
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
6 changes: 4 additions & 2 deletions common/src/main/java/bisq/common/util/Tuple2.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

import java.io.Serializable;

import java.util.Objects;

public class Tuple2<A, B> implements Serializable {
private static final long serialVersionUID = 1;

Expand All @@ -38,8 +40,8 @@ public boolean equals(Object o) {

Tuple2<?, ?> tuple2 = (Tuple2<?, ?>) o;

if (first != null ? !first.equals(tuple2.first) : tuple2.first != null) return false;
return !(second != null ? !second.equals(tuple2.second) : tuple2.second != null);
if (!Objects.equals(first, tuple2.first)) return false;
return Objects.equals(second, tuple2.second);

}

Expand Down
8 changes: 5 additions & 3 deletions common/src/main/java/bisq/common/util/Tuple3.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

package bisq.common.util;

import java.util.Objects;

public class Tuple3<A, B, C> {
final public A first;
final public B second;
Expand All @@ -36,9 +38,9 @@ public boolean equals(Object o) {

Tuple3<?, ?, ?> tuple3 = (Tuple3<?, ?, ?>) o;

if (first != null ? !first.equals(tuple3.first) : tuple3.first != null) return false;
if (second != null ? !second.equals(tuple3.second) : tuple3.second != null) return false;
return !(third != null ? !third.equals(tuple3.third) : tuple3.third != null);
if (!Objects.equals(first, tuple3.first)) return false;
if (!Objects.equals(second, tuple3.second)) return false;
return Objects.equals(third, tuple3.third);

}

Expand Down
18 changes: 10 additions & 8 deletions common/src/main/java/bisq/common/util/Tuple4.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,19 @@

package bisq.common.util;

import java.util.Objects;

public class Tuple4<A, B, C, D> {
final public A first;
final public B second;
final public C third;
final public D forth;
final public D fourth;

public Tuple4(A first, B second, C third, D forth) {
public Tuple4(A first, B second, C third, D fourth) {
this.first = first;
this.second = second;
this.third = third;
this.forth = forth;
this.fourth = fourth;
}

@SuppressWarnings("SimplifiableIfStatement")
Expand All @@ -38,10 +40,10 @@ public boolean equals(Object o) {

Tuple4<?, ?, ?, ?> tuple4 = (Tuple4<?, ?, ?, ?>) o;

if (first != null ? !first.equals(tuple4.first) : tuple4.first != null) return false;
if (second != null ? !second.equals(tuple4.second) : tuple4.second != null) return false;
if (third != null ? !third.equals(tuple4.third) : tuple4.third != null) return false;
return !(forth != null ? !forth.equals(tuple4.forth) : tuple4.forth != null);
if (!Objects.equals(first, tuple4.first)) return false;
if (!Objects.equals(second, tuple4.second)) return false;
if (!Objects.equals(third, tuple4.third)) return false;
return Objects.equals(fourth, tuple4.fourth);

}

Expand All @@ -50,7 +52,7 @@ public int hashCode() {
int result = first != null ? first.hashCode() : 0;
result = 31 * result + (second != null ? second.hashCode() : 0);
result = 31 * result + (third != null ? third.hashCode() : 0);
result = 31 * result + (forth != null ? forth.hashCode() : 0);
result = 31 * result + (fourth != null ? fourth.hashCode() : 0);
return result;
}
}
61 changes: 61 additions & 0 deletions common/src/main/java/bisq/common/util/Tuple5.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* 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.common.util;

import java.util.Objects;

public class Tuple5<A, B, C, D, E> {
final public A first;
final public B second;
final public C third;
final public D fourth;
final public E fifth;

public Tuple5(A first, B second, C third, D fourth, E fifth) {
this.first = first;
this.second = second;
this.third = third;
this.fourth = fourth;
this.fifth = fifth;
}

@SuppressWarnings("SimplifiableIfStatement")
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Tuple5)) return false;

Tuple5<?, ?, ?, ?, ?> tuple5 = (Tuple5<?, ?, ?, ?, ?>) o;

if (!Objects.equals(first, tuple5.first)) return false;
if (!Objects.equals(second, tuple5.second)) return false;
if (!Objects.equals(third, tuple5.third)) return false;
if (!Objects.equals(fourth, tuple5.fourth)) return false;
return Objects.equals(fifth, tuple5.fifth);
}

@Override
public int hashCode() {
int result = first != null ? first.hashCode() : 0;
result = 31 * result + (second != null ? second.hashCode() : 0);
result = 31 * result + (third != null ? third.hashCode() : 0);
result = 31 * result + (fourth != null ? fourth.hashCode() : 0);
result = 31 * result + (fifth != null ? fifth.hashCode() : 0);
return result;
}
}
80 changes: 50 additions & 30 deletions desktop/src/main/java/bisq/desktop/components/PeerInfoIcon.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,10 @@
import bisq.core.payment.payload.PaymentMethod;
import bisq.core.trade.Trade;
import bisq.core.user.Preferences;
import bisq.core.util.BSFormatter;

import bisq.network.p2p.NodeAddress;

import bisq.common.util.Tuple3;
import bisq.common.util.Tuple5;

import com.google.common.base.Charsets;

Expand Down Expand Up @@ -69,10 +68,9 @@ public class PeerInfoIcon extends Group {
private final Map<String, String> peerTagMap;
private final Label numTradesLabel;
private final Label tagLabel;
protected final Pane tagPane;
protected final Pane numTradesPane;
final Pane tagPane;
final Pane numTradesPane;
private final String fullAddress;
private final double scaleFactor;

public PeerInfoIcon(NodeAddress nodeAddress,
String role,
Expand All @@ -81,7 +79,6 @@ public PeerInfoIcon(NodeAddress nodeAddress,
Offer offer,
Preferences preferences,
AccountAgeWitnessService accountAgeWitnessService,
BSFormatter formatter,
boolean useDevPrivilegeKeys) {
this(nodeAddress,
role,
Expand All @@ -91,7 +88,6 @@ public PeerInfoIcon(NodeAddress nodeAddress,
null,
preferences,
accountAgeWitnessService,
formatter,
useDevPrivilegeKeys);

}
Expand All @@ -103,7 +99,6 @@ public PeerInfoIcon(NodeAddress nodeAddress,
Trade trade,
Preferences preferences,
AccountAgeWitnessService accountAgeWitnessService,
BSFormatter formatter,
boolean useDevPrivilegeKeys) {
this(nodeAddress,
role,
Expand All @@ -113,7 +108,6 @@ public PeerInfoIcon(NodeAddress nodeAddress,
trade,
preferences,
accountAgeWitnessService,
formatter,
useDevPrivilegeKeys);
}

Expand All @@ -125,18 +119,21 @@ private PeerInfoIcon(NodeAddress nodeAddress,
@Nullable Trade trade,
Preferences preferences,
AccountAgeWitnessService accountAgeWitnessService,
BSFormatter formatter,
boolean useDevPrivilegeKeys) {
this.numTrades = numTrades;
this.accountAgeWitnessService = accountAgeWitnessService;

scaleFactor = getScaleFactor();
double scaleFactor = getScaleFactor();
fullAddress = nodeAddress != null ? nodeAddress.getFullAddress() : "";

peerTagMap = preferences.getPeerTagMap();

boolean hasTraded = numTrades > 0;
Tuple3<Long, String, String> peersAccount = getPeersAccountAge(trade, offer);
Tuple5<Long, Long, String, String, String> peersAccount = getPeersAccountAge(trade, offer);

Long accountAge = peersAccount.first;
Long signAge = peersAccount.second;

if (offer == null) {
checkNotNull(trade, "Trade must not be null if offer is null.");
offer = trade.getOffer();
Expand All @@ -146,19 +143,19 @@ private PeerInfoIcon(NodeAddress nodeAddress,

boolean isFiatCurrency = CurrencyUtil.isFiatCurrency(offer.getCurrencyCode());

String accountAge = isFiatCurrency ?
peersAccount.first > -1 ? Res.get("peerInfoIcon.tooltip.age", DisplayUtils.formatAccountAge(peersAccount.first)) :
String accountAgeTooltip = isFiatCurrency ?
accountAge > -1 ? Res.get("peerInfoIcon.tooltip.age", DisplayUtils.formatAccountAge(accountAge)) :
Res.get("peerInfoIcon.tooltip.unknownAge") :
"";
tooltipText = hasTraded ?
Res.get("peerInfoIcon.tooltip.trade.traded", role, fullAddress, numTrades, accountAge) :
Res.get("peerInfoIcon.tooltip.trade.notTraded", role, fullAddress, accountAge);
Res.get("peerInfoIcon.tooltip.trade.traded", role, fullAddress, numTrades, accountAgeTooltip) :
Res.get("peerInfoIcon.tooltip.trade.notTraded", role, fullAddress, accountAgeTooltip);

// outer circle
Color ringColor;
if (isFiatCurrency) {

switch (accountAgeWitnessService.getPeersAccountAgeCategory(peersAccount.first)) {
switch (accountAgeWitnessService.getPeersAccountAgeCategory(hasChargebackRisk(trade, offer) ? signAge : accountAge)) {
case TWO_MONTHS_OR_MORE:
ringColor = Color.rgb(0, 225, 0); // > 2 months green
break;
Expand Down Expand Up @@ -249,20 +246,26 @@ private PeerInfoIcon(NodeAddress nodeAddress,

getChildren().addAll(outerBackground, innerBackground, avatarImageView, tagPane, numTradesPane);

addMouseListener(numTrades, privateNotificationManager, offer, preferences, formatter, useDevPrivilegeKeys,
isFiatCurrency, peersAccount.first, peersAccount.second, peersAccount.third);
addMouseListener(numTrades, privateNotificationManager, offer, preferences, useDevPrivilegeKeys,
isFiatCurrency, accountAge, signAge, peersAccount.third, peersAccount.fourth, peersAccount.fifth);
}

// Return Sign age, account info, sign state
private Tuple3<Long, String, String> getPeersAccountAge(@Nullable Trade trade, @Nullable Offer offer) {
/**
* @param trade Open trade for trading peer info to be shown
* @param offer Open offer for trading peer info to be shown
* @return account age, sign age, account info, sign info, sign state
*/
private Tuple5<Long, Long, String, String, String> getPeersAccountAge(@Nullable Trade trade,
@Nullable Offer offer) {
AccountAgeWitnessService.SignState signState;
long signAge = -1L;
long accountAge = -1L;

if (trade != null) {
offer = trade.getOffer();
if (offer == null) {
// unexpected
return new Tuple3<>(-1L, Res.get("peerInfo.age.noRisk"), null);
return new Tuple5<>(signAge, accountAge, Res.get("peerInfo.age.noRisk"), null, null);
}
signState = accountAgeWitnessService.getSignState(trade);
signAge = accountAgeWitnessService.getWitnessSignAge(trade, new Date());
Expand All @@ -273,39 +276,56 @@ private Tuple3<Long, String, String> getPeersAccountAge(@Nullable Trade trade, @
signAge = accountAgeWitnessService.getWitnessSignAge(offer, new Date());
accountAge = accountAgeWitnessService.getAccountAge(offer);
}
if (PaymentMethod.hasChargebackRisk(offer.getPaymentMethod(), offer.getCurrencyCode())) {
String accountAgeInfo = Res.get("peerInfo.age.chargeBackRisk");

if (hasChargebackRisk(trade, offer)) {
String signAgeInfo = Res.get("peerInfo.age.chargeBackRisk");
String accountSigningState = StringUtils.capitalize(signState.getPresentation());
if (signState.equals(AccountAgeWitnessService.SignState.UNSIGNED))
accountAgeInfo = null;
signAgeInfo = null;

return new Tuple3<>(signAge, accountAgeInfo, accountSigningState);
return new Tuple5<>(accountAge, signAge, Res.get("peerInfo.age.noRisk"), signAgeInfo, accountSigningState);
}
return new Tuple3<>(accountAge, Res.get("peerInfo.age.noRisk"), null);
return new Tuple5<>(accountAge, signAge, Res.get("peerInfo.age.noRisk"), null, null);
}

private boolean hasChargebackRisk(@Nullable Trade trade, @Nullable Offer offer) {
Offer offerToCheck = trade != null ? trade.getOffer() : offer;

return offerToCheck != null &&
PaymentMethod.hasChargebackRisk(offerToCheck.getPaymentMethod(), offerToCheck.getCurrencyCode());
}

protected void addMouseListener(int numTrades,
PrivateNotificationManager privateNotificationManager,
Offer offer,
Preferences preferences,
BSFormatter formatter,
boolean useDevPrivilegeKeys,
boolean isFiatCurrency,
long peersAccountAge,
long peersSignAge,
String peersAccountAgeInfo,
String peersSignAgeInfo,
String accountSigningState) {

final String accountAgeTagEditor = isFiatCurrency && peersAccountAgeInfo != null ?
final String accountAgeFormatted = isFiatCurrency ?
peersAccountAge > -1 ?
DisplayUtils.formatAccountAge(peersAccountAge) :
Res.get("peerInfo.unknownAge") :
null;

final String signAgeFormatted = isFiatCurrency && peersSignAgeInfo != null ?
peersSignAge > -1 ?
DisplayUtils.formatAccountAge(peersSignAge) :
Res.get("peerInfo.unknownAge") :
null;

setOnMouseClicked(e -> new PeerInfoWithTagEditor(privateNotificationManager, offer, preferences, useDevPrivilegeKeys)
.fullAddress(fullAddress)
.numTrades(numTrades)
.accountAge(accountAgeTagEditor)
.accountAge(accountAgeFormatted)
.signAge(signAgeFormatted)
.accountAgeInfo(peersAccountAgeInfo)
.signAgeInfo(peersSignAgeInfo)
.accountSigningState(accountSigningState)
.position(localToScene(new Point2D(0, 0)))
.onSave(newTag -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ public PeerInfoIconSmall(NodeAddress nodeAddress,
offer,
preferences,
accountAgeWitnessService,
formatter,
useDevPrivilegeKeys);
}

Expand All @@ -37,11 +36,12 @@ protected void addMouseListener(int numTrades,
PrivateNotificationManager privateNotificationManager,
Offer offer,
Preferences preferences,
BSFormatter formatter,
boolean useDevPrivilegeKeys,
boolean isFiatCurrency,
long peersAccountAge,
long peersSignAge,
String peersAccountAgeInfo,
String peersSignAgeInfo,
String accountSigningState) {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ private void addHolderNameAndIdForDisplayAccount() {
TextField holderNameTextField = tuple.second;
holderNameTextField.setText(bankAccountPayload.getHolderName());
holderNameTextField.setMinWidth(250);
tuple.forth.setText(bankAccountPayload.getHolderTaxId());
tuple.fourth.setText(bankAccountPayload.getHolderTaxId());
} else {
addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.account.owner"), bankAccountPayload.getHolderName());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ private void addHolderNameAndIdForDisplayAccount() {
TextField holderNameTextField = tuple.second;
holderNameTextField.setText(cashDepositAccountPayload.getHolderName());
holderNameTextField.setMinWidth(300);
tuple.forth.setText(cashDepositAccountPayload.getHolderTaxId());
tuple.fourth.setText(cashDepositAccountPayload.getHolderTaxId());
} else {
addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.account.owner"),
cashDepositAccountPayload.getHolderName());
Expand Down
Loading