Skip to content

Commit 633e290

Browse files
committed
add paysafe payment method
1 parent 71fab72 commit 633e290

26 files changed

+409
-4
lines changed

core/src/main/java/haveno/core/api/model/PaymentAccountForm.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ public enum FormId {
7777
AUSTRALIA_PAYID,
7878
CASH_APP,
7979
PAYPAL,
80-
VENMO;
80+
VENMO,
81+
PAYSAFE;
8182

8283
public static PaymentAccountForm.FormId fromProto(protobuf.PaymentAccountForm.FormId formId) {
8384
return ProtoUtil.enumFromProto(PaymentAccountForm.FormId.class, formId.name());

core/src/main/java/haveno/core/payment/PaymentAccountFactory.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ public static PaymentAccount getPaymentAccount(PaymentMethod paymentMethod) {
136136
return new CashAppAccount();
137137
case PaymentMethod.VENMO_ID:
138138
return new VenmoAccount();
139+
case PaymentMethod.PAYSAFE_ID:
140+
return new PaysafeAccount();
139141

140142
// Cannot be deleted as it would break old trade history entries
141143
case PaymentMethod.OK_PAY_ID:
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* This file is part of Haveno.
3+
*
4+
* Haveno is free software: you can redistribute it and/or modify it
5+
* under the terms of the GNU Affero General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or (at
7+
* your option) any later version.
8+
*
9+
* Haveno is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
12+
* License for more details.
13+
*
14+
* You should have received a copy of the GNU Affero General Public License
15+
* along with Haveno. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
package haveno.core.payment;
19+
20+
import haveno.core.api.model.PaymentAccountFormField;
21+
import haveno.core.locale.TraditionalCurrency;
22+
import haveno.core.locale.TradeCurrency;
23+
import haveno.core.payment.payload.PaymentAccountPayload;
24+
import haveno.core.payment.payload.PaymentMethod;
25+
import haveno.core.payment.payload.PaysafeAccountPayload;
26+
import lombok.EqualsAndHashCode;
27+
import org.jetbrains.annotations.NotNull;
28+
29+
import java.util.List;
30+
31+
@EqualsAndHashCode(callSuper = true)
32+
public final class PaysafeAccount extends PaymentAccount {
33+
34+
private static final List<PaymentAccountFormField.FieldId> INPUT_FIELD_IDS = List.of(
35+
PaymentAccountFormField.FieldId.ACCOUNT_NAME,
36+
PaymentAccountFormField.FieldId.EMAIL,
37+
PaymentAccountFormField.FieldId.TRADE_CURRENCIES,
38+
PaymentAccountFormField.FieldId.SALT
39+
);
40+
41+
// https://developer.paysafe.com/en/support/reference-information/codes/
42+
public static final List<TradeCurrency> SUPPORTED_CURRENCIES = List.of(
43+
new TraditionalCurrency("AED"),
44+
new TraditionalCurrency("ARS"),
45+
new TraditionalCurrency("AUD"),
46+
new TraditionalCurrency("BGN"),
47+
new TraditionalCurrency("BRL"),
48+
new TraditionalCurrency("CAD"),
49+
new TraditionalCurrency("CHF"),
50+
new TraditionalCurrency("CZK"),
51+
new TraditionalCurrency("DKK"),
52+
new TraditionalCurrency("EGP"),
53+
new TraditionalCurrency("EUR"),
54+
new TraditionalCurrency("GBP"),
55+
new TraditionalCurrency("GEL"),
56+
new TraditionalCurrency("HRK"),
57+
new TraditionalCurrency("HUF"),
58+
new TraditionalCurrency("ILS"),
59+
new TraditionalCurrency("INR"),
60+
new TraditionalCurrency("JPY"),
61+
new TraditionalCurrency("ISK"),
62+
new TraditionalCurrency("KWD"),
63+
new TraditionalCurrency("KRW"),
64+
new TraditionalCurrency("MXN"),
65+
new TraditionalCurrency("NOK"),
66+
new TraditionalCurrency("NZD"),
67+
new TraditionalCurrency("PEN"),
68+
new TraditionalCurrency("PHP"),
69+
new TraditionalCurrency("PLN"),
70+
new TraditionalCurrency("RON"),
71+
new TraditionalCurrency("RSD"),
72+
new TraditionalCurrency("RUB"),
73+
new TraditionalCurrency("SAR"),
74+
new TraditionalCurrency("SEK"),
75+
new TraditionalCurrency("TRY"),
76+
new TraditionalCurrency("USD"),
77+
new TraditionalCurrency("UYU")
78+
);
79+
80+
public PaysafeAccount() {
81+
super(PaymentMethod.PAYSAFE);
82+
}
83+
84+
@Override
85+
protected PaymentAccountPayload createPayload() {
86+
return new PaysafeAccountPayload(paymentMethod.getId(), id);
87+
}
88+
89+
@Override
90+
public @NotNull List<TradeCurrency> getSupportedCurrencies() {
91+
return SUPPORTED_CURRENCIES;
92+
}
93+
94+
@Override
95+
public @NotNull List<PaymentAccountFormField.FieldId> getInputFieldIds() {
96+
return INPUT_FIELD_IDS;
97+
}
98+
99+
public void setEmail(String accountId) {
100+
((PaysafeAccountPayload) paymentAccountPayload).setEmail(accountId);
101+
}
102+
103+
public String getEmail() {
104+
return ((PaysafeAccountPayload) paymentAccountPayload).getEmail();
105+
}
106+
107+
@Override
108+
protected PaymentAccountFormField getEmptyFormField(PaymentAccountFormField.FieldId fieldId) {
109+
var field = super.getEmptyFormField(fieldId);
110+
if (field.getId() == PaymentAccountFormField.FieldId.TRADE_CURRENCIES) field.setValue("");
111+
return field;
112+
}
113+
}

core/src/main/java/haveno/core/payment/payload/PaymentMethod.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import haveno.core.payment.CashAtAtmAccount;
5252
import haveno.core.payment.PayByMailAccount;
5353
import haveno.core.payment.PayPalAccount;
54+
import haveno.core.payment.PaysafeAccount;
5455
import haveno.core.payment.CashDepositAccount;
5556
import haveno.core.payment.CelPayAccount;
5657
import haveno.core.payment.ZelleAccount;
@@ -193,6 +194,7 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme
193194
public static final String CASH_APP_ID = "CASH_APP";
194195
public static final String VENMO_ID = "VENMO";
195196
public static final String PAYPAL_ID = "PAYPAL";
197+
public static final String PAYSAFE_ID = "PAYSAFE";
196198

197199
public static PaymentMethod UPHOLD;
198200
public static PaymentMethod MONEY_BEAM;
@@ -252,6 +254,7 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme
252254
public static PaymentMethod PAYPAL;
253255
public static PaymentMethod CASH_APP;
254256
public static PaymentMethod VENMO;
257+
public static PaymentMethod PAYSAFE;
255258

256259
// Cannot be deleted as it would break old trade history entries
257260
@Deprecated
@@ -322,6 +325,7 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme
322325
DOMESTIC_WIRE_TRANSFER = new PaymentMethod(DOMESTIC_WIRE_TRANSFER_ID, 3 * DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(DomesticWireTransferAccount.SUPPORTED_CURRENCIES)),
323326
PAYPAL = new PaymentMethod(PAYPAL_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(PayPalAccount.SUPPORTED_CURRENCIES)),
324327
CASH_APP = new PaymentMethod(CASH_APP_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(CashAppAccount.SUPPORTED_CURRENCIES)),
328+
PAYSAFE = new PaymentMethod(PaymentMethod.PAYSAFE_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(PaysafeAccount.SUPPORTED_CURRENCIES)),
325329

326330
// Japan
327331
JAPAN_BANK = new PaymentMethod(JAPAN_BANK_ID, DAY, DEFAULT_TRADE_LIMIT_LOW_RISK, getAssetCodes(JapanBankAccount.SUPPORTED_CURRENCIES)),
@@ -364,7 +368,8 @@ public static List<PaymentMethod> getPaymentMethods() {
364368
AUSTRALIA_PAYID_ID,
365369
CASH_APP_ID,
366370
PAYPAL_ID,
367-
VENMO_ID);
371+
VENMO_ID,
372+
PAYSAFE_ID);
368373
return paymentMethods.stream().filter(paymentMethod -> paymentMethodIds.contains(paymentMethod.getId())).collect(Collectors.toList());
369374
}
370375

@@ -588,7 +593,8 @@ public static boolean hasChargebackRisk(String id, String currencyCode) {
588593
id.equals(PaymentMethod.UPHOLD_ID) ||
589594
id.equals(PaymentMethod.CASH_APP_ID) ||
590595
id.equals(PaymentMethod.PAYPAL_ID) ||
591-
id.equals(PaymentMethod.VENMO_ID);
596+
id.equals(PaymentMethod.VENMO_ID) ||
597+
id.equals(PaymentMethod.PAYSAFE_ID);
592598
}
593599

594600
public static boolean isRoundedForAtmCash(String id) {
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* This file is part of Haveno.
3+
*
4+
* Haveno is free software: you can redistribute it and/or modify it
5+
* under the terms of the GNU Affero General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or (at
7+
* your option) any later version.
8+
*
9+
* Haveno is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
12+
* License for more details.
13+
*
14+
* You should have received a copy of the GNU Affero General Public License
15+
* along with Haveno. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
package haveno.core.payment.payload;
19+
20+
import com.google.protobuf.Message;
21+
import haveno.core.locale.Res;
22+
import lombok.EqualsAndHashCode;
23+
import lombok.Getter;
24+
import lombok.Setter;
25+
import lombok.ToString;
26+
import lombok.extern.slf4j.Slf4j;
27+
28+
import java.nio.charset.StandardCharsets;
29+
import java.util.HashMap;
30+
import java.util.Map;
31+
32+
@EqualsAndHashCode(callSuper = true)
33+
@ToString
34+
@Setter
35+
@Getter
36+
@Slf4j
37+
public final class PaysafeAccountPayload extends PaymentAccountPayload {
38+
private String email = "";
39+
40+
public PaysafeAccountPayload(String paymentMethod, String id) {
41+
super(paymentMethod, id);
42+
}
43+
44+
45+
///////////////////////////////////////////////////////////////////////////////////////////
46+
// PROTO BUFFER
47+
///////////////////////////////////////////////////////////////////////////////////////////
48+
49+
private PaysafeAccountPayload(String paymentMethod,
50+
String id,
51+
String email,
52+
long maxTradePeriod,
53+
Map<String, String> excludeFromJsonDataMap) {
54+
super(paymentMethod,
55+
id,
56+
maxTradePeriod,
57+
excludeFromJsonDataMap);
58+
59+
this.email = email;
60+
}
61+
62+
@Override
63+
public Message toProtoMessage() {
64+
return getPaymentAccountPayloadBuilder()
65+
.setPaysafeAccountPayload(protobuf.PaysafeAccountPayload.newBuilder().setEmail(email))
66+
.build();
67+
}
68+
69+
public static PaysafeAccountPayload fromProto(protobuf.PaymentAccountPayload proto) {
70+
return new PaysafeAccountPayload(proto.getPaymentMethodId(),
71+
proto.getId(),
72+
proto.getPaysafeAccountPayload().getEmail(),
73+
proto.getMaxTradePeriod(),
74+
new HashMap<>(proto.getExcludeFromJsonDataMap()));
75+
}
76+
77+
78+
///////////////////////////////////////////////////////////////////////////////////////////
79+
// API
80+
///////////////////////////////////////////////////////////////////////////////////////////
81+
82+
@Override
83+
public String getPaymentDetails() {
84+
return Res.get(paymentMethodId) + " - " + Res.getWithCol("payment.email") + " " + email;
85+
}
86+
87+
@Override
88+
public String getPaymentDetailsForTradePopup() {
89+
return getPaymentDetails();
90+
}
91+
92+
@Override
93+
public byte[] getAgeWitnessInputData() {
94+
return super.getAgeWitnessInputData(email.getBytes(StandardCharsets.UTF_8));
95+
}
96+
}

core/src/main/java/haveno/core/proto/CoreProtoResolver.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import haveno.core.payment.payload.OKPayAccountPayload;
5555
import haveno.core.payment.payload.PaxumAccountPayload;
5656
import haveno.core.payment.payload.PaymentAccountPayload;
57+
import haveno.core.payment.payload.PaysafeAccountPayload;
5758
import haveno.core.payment.payload.PayPalAccountPayload;
5859
import haveno.core.payment.payload.PayseraAccountPayload;
5960
import haveno.core.payment.payload.PaytmAccountPayload;
@@ -239,6 +240,8 @@ public PaymentAccountPayload fromProto(protobuf.PaymentAccountPayload proto) {
239240
return VenmoAccountPayload.fromProto(proto);
240241
case PAYPAL_ACCOUNT_PAYLOAD:
241242
return PayPalAccountPayload.fromProto(proto);
243+
case PAYSAFE_ACCOUNT_PAYLOAD:
244+
return PaysafeAccountPayload.fromProto(proto);
242245

243246
default:
244247
throw new ProtobufferRuntimeException("Unknown proto message case(PB.PaymentAccountPayload). messageCase=" + messageCase);

core/src/main/resources/i18n/displayStrings.properties

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3067,6 +3067,9 @@ payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send
30673067
- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat \
30683068
to tell your trading peer the reference text you picked so they can verify your payment)\n\
30693069
- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it)
3070+
payment.paysafe.info=For your protection, we strongly discourage using Paysafecard PINs for payment.\n\n\
3071+
Transactions made via PINs cannot be independently verified for dispute resolution. If an issue arises, recovering funds may not be possible.\n\n\
3072+
To ensure transaction security with dispute resolution, always use payment methods that provide verifiable records.
30703073

30713074
# We use constants from the code so we do not use our normal naming convention
30723075
# dynamic values are not recognized by IntelliJ
@@ -3302,6 +3305,8 @@ CASH_APP_SHORT=Cash App
33023305
# suppress inspection "UnusedProperty"
33033306
VENMO_SHORT=Venmo
33043307
PAYPAL_SHORT=PayPal
3308+
# suppress inspection "UnusedProperty"
3309+
PAYSAFE=Paysafe
33053310

33063311

33073312
####################################################################

core/src/main/resources/i18n/displayStrings_cs.properties

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3065,6 +3065,10 @@ payment.amazonGiftCard.info=Chcete-li platit dárkovou kartou Amazon eGift, bude
30653065
- Na kartě do zprávy pro příjemce můžete přidat i vlastní originální text (např. "Happy birthday Susan!") spolu s ID obchodu (v takovém případě \
30663066
o tom informujte protistranu pomocí obchodovacího chatu, aby mohli s jistotou ověřit, že obdržená dárková karta pochází od vás.)\n\
30673067
- Karty Amazon eGift lze uplatnit pouze na té stránce Amazon, na které byly také koupeny (např. karta koupená na amazon.it může být uplatněna zase jen na amazon.it).
3068+
payment.paysafe.info=Pro vaši ochranu důrazně nedoporučujeme používat Paysafecard PINy pro platby.\n\n\
3069+
Transakce provedené pomocí PINů nelze nezávisle ověřit pro řešení sporů. Pokud nastane problém, obnova prostředků nemusí být možná.\n\n\
3070+
Pro zajištění bezpečnosti transakcí a podpory řešení sporů vždy používejte platební metody, které poskytují ověřitelné záznamy.
3071+
30683072

30693073
# We use constants from the code so we do not use our normal naming convention
30703074
# dynamic values are not recognized by IntelliJ

core/src/main/resources/i18n/displayStrings_de.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2047,6 +2047,9 @@ payment.australia.payid=PayID
20472047
payment.payid=PayIDs wie E-Mail Adressen oder Telefonnummern die mit Finanzinstitutionen verbunden sind.
20482048
payment.payid.info=Eine PayID wie eine Telefonnummer, E-Mail Adresse oder Australische Business Number (ABN) mit der Sie sicher Ihre Bank, Kreditgenossenschaft oder Bausparkassenkonto verlinken können. Sie müssen bereits eine PayID mit Ihrer Australischen Finanzinstitution erstellt haben. Beide Institutionen, die die sendet und die die empfängt, müssen PayID unterstützen. Weitere informationen finden Sie unter [HYPERLINK:https://payid.com.au/faqs/]
20492049
payment.amazonGiftCard.info=Um mit einer Amazon eGift Geschenkkarte zu bezahlen, müssen Sie eine Amazon eGift Geschenkkarte über Ihr Amazon-Konto an den XMR-Verkäufer senden. \n\nHaveno zeigt die E-Mail-Adresse oder Telefonnummer des XMR-Verkäufers an, an die die Geschenkkarte gesendet werden soll, und Sie müssen die Handels-ID in das Nachrichtenfeld der Geschenkkarte eintragen. Bitte lesen Sie das Wiki [HYPERLINK:https://haveno.exchange/wiki/Amazon_eGift_card] für weitere Details und empfohlene Vorgehensweisen. \n\nDrei wichtige Hinweise:\n- Versuchen Sie Geschenkkarten mit Beträgen von 100 USD oder weniger zu versenden, weil Amazon größere Geschenkkarten gerne als betrügerisch kennzeichnet\n- Versuchen Sie einen kreativen, glaubwürdigen Text für die Nachricht der Geschenkkarten zu verwenden (z.B. "Alles Gute zum Geburtstag Susi!"), zusammen mit der Handels-ID (und verwenden Sie den Handels-Chat, um Ihrem Handelspartner den von Ihnen gewählten Referenztext mitzuteilen, damit er Ihre Zahlung überprüfen kann)\n- Amazon Geschenkkarten können nur auf der Amazon-Website eingelöst werden, auf der sie gekauft wurden (z. B. kann eine auf amazon.it gekaufte Geschenkkarte nur auf amazon.it eingelöst werden)
2050+
payment.paysafe.info=Zum Schutz Ihrer Sicherheit raten wir dringend davon ab, Paysafecard-PINs für Zahlungen zu verwenden.\n\n\
2051+
Transaktionen, die über PINs durchgeführt werden, können nicht unabhängig zur Streitbeilegung überprüft werden. Wenn ein Problem auftritt, kann die Rückerstattung von Geldern möglicherweise nicht möglich sein.\n\n\
2052+
Um die Transaktionssicherheit mit Streitbeilegung zu gewährleisten, verwenden Sie immer Zahlungsmethoden, die überprüfbare Aufzeichnungen bieten.
20502053

20512054

20522055
# We use constants from the code so we do not use our normal naming convention

core/src/main/resources/i18n/displayStrings_es.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2048,6 +2048,9 @@ payment.australia.payid=PayID
20482048
payment.payid=PayID conectado a una institución financiera. Como la dirección email o el número de móvil.
20492049
payment.payid.info=Un PayID como un número de teléfono, dirección email o Australian Business Number (ABN), que puede conectar con seguridad a su banco, unión de crédito o cuenta de construcción de sociedad. Necesita haber creado una PayID con su institución financiera australiana. Tanto para enviar y recibir las instituciones financieras deben soportar PayID. Para más información por favor compruebe [HYPERLINK:https://payid.com.au/faqs/]
20502050
payment.amazonGiftCard.info=Para pagar con Tarjeta eGift Amazon. necesitará enviar una Tarjeta eGift Amazon al vendedor XMR a través de su cuenta Amazon.\n\nHaveno mostrará la dirección e-mail del vendedor de XMR o el número de teléfono donde la tarjeta de regalo deberá enviarse. Por favor vea la wiki [HYPERLINK:https://haveno.exchange/wiki/Amazon_eGift_card] para más detalles y mejores prácticas.\n\nNotas importantes:\n- Pruebe a enviar las tarjetas regalo en cantidades de 100USD o menores, ya que Amazon está señalando tarjetas regalo mayores como fraudulentas.\n- Intente usar textos para el mensaje de la tarjeta regalo creíbles y creativos ("Feliz cumpleaños!").\n- Las tarjetas Amazon eGift pueden ser redimidas únicamente en la web de Amazon en la que se compraron (por ejemplo, una tarjeta comprada en amazon.it solo puede ser redimida en amazon.it)
2051+
payment.paysafe.info=Por su protección, desaconsejamos encarecidamente el uso de PINs de Paysafecard para pagos.\n\n\
2052+
Las transacciones realizadas mediante PINs no pueden ser verificadas de forma independiente para la resolución de disputas. Si surge un problema, recuperar los fondos puede no ser posible.\n\n\
2053+
Para garantizar la seguridad de las transacciones con resolución de disputas, utilice siempre métodos de pago que proporcionen registros verificables.
20512054

20522055

20532056
# We use constants from the code so we do not use our normal naming convention

0 commit comments

Comments
 (0)