From 9932ae84f4a0f53d5e217d060ef62e8abf2830fe Mon Sep 17 00:00:00 2001 From: woodser <13068859+woodser@users.noreply.github.com> Date: Fri, 20 Jun 2025 18:41:16 -0400 Subject: [PATCH] support interac e-transfer payment accounts over grpc api --- .../core/api/CorePaymentAccountsService.java | 11 ++++-- .../core/api/model/PaymentAccountForm.java | 3 +- .../core/payment/InteracETransferAccount.java | 36 +++++++++++++++++-- .../haveno/core/payment/PaymentAccount.java | 8 +++-- .../InteracETransferAccountPayload.java | 16 ++++----- .../core/payment/payload/PaymentMethod.java | 3 +- .../java/haveno/core/trade/HavenoUtils.java | 2 ++ .../paymentmethods/InteracETransferForm.java | 2 +- proto/src/main/proto/pb.proto | 3 +- 9 files changed, 65 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/haveno/core/api/CorePaymentAccountsService.java b/core/src/main/java/haveno/core/api/CorePaymentAccountsService.java index b506a00ac1..b6afd098b7 100644 --- a/core/src/main/java/haveno/core/api/CorePaymentAccountsService.java +++ b/core/src/main/java/haveno/core/api/CorePaymentAccountsService.java @@ -36,6 +36,8 @@ import haveno.core.payment.InstantCryptoCurrencyAccount; import haveno.core.payment.PaymentAccount; import haveno.core.payment.PaymentAccountFactory; import haveno.core.payment.payload.PaymentMethod; +import haveno.core.payment.validation.InteracETransferValidator; +import haveno.core.trade.HavenoUtils; import haveno.core.user.User; import java.io.File; import static java.lang.String.format; @@ -48,19 +50,24 @@ import lombok.extern.slf4j.Slf4j; @Singleton @Slf4j -class CorePaymentAccountsService { +public class CorePaymentAccountsService { private final CoreAccountService accountService; private final AccountAgeWitnessService accountAgeWitnessService; private final User user; + public final InteracETransferValidator interacETransferValidator; @Inject public CorePaymentAccountsService(CoreAccountService accountService, AccountAgeWitnessService accountAgeWitnessService, - User user) { + User user, + InteracETransferValidator interacETransferValidator) { this.accountService = accountService; this.accountAgeWitnessService = accountAgeWitnessService; this.user = user; + this.interacETransferValidator = interacETransferValidator; + + HavenoUtils.corePaymentAccountService = this; } PaymentAccount createPaymentAccount(PaymentAccountForm form) { diff --git a/core/src/main/java/haveno/core/api/model/PaymentAccountForm.java b/core/src/main/java/haveno/core/api/model/PaymentAccountForm.java index 72f9dbc51a..34ed649266 100644 --- a/core/src/main/java/haveno/core/api/model/PaymentAccountForm.java +++ b/core/src/main/java/haveno/core/api/model/PaymentAccountForm.java @@ -84,7 +84,8 @@ public final class PaymentAccountForm implements PersistablePayload { SWISH, TRANSFERWISE_USD, AMAZON_GIFT_CARD, - ACH_TRANSFER; + ACH_TRANSFER, + INTERAC_E_TRANSFER; public static PaymentAccountForm.FormId fromProto(protobuf.PaymentAccountForm.FormId formId) { return ProtoUtil.enumFromProto(PaymentAccountForm.FormId.class, formId.name()); diff --git a/core/src/main/java/haveno/core/payment/InteracETransferAccount.java b/core/src/main/java/haveno/core/payment/InteracETransferAccount.java index 579167c276..e1929b09e4 100644 --- a/core/src/main/java/haveno/core/payment/InteracETransferAccount.java +++ b/core/src/main/java/haveno/core/payment/InteracETransferAccount.java @@ -17,12 +17,15 @@ package haveno.core.payment; +import haveno.core.api.model.PaymentAccountForm; import haveno.core.api.model.PaymentAccountFormField; import haveno.core.locale.TraditionalCurrency; import haveno.core.locale.TradeCurrency; import haveno.core.payment.payload.InteracETransferAccountPayload; import haveno.core.payment.payload.PaymentAccountPayload; import haveno.core.payment.payload.PaymentMethod; +import haveno.core.payment.validation.InteracETransferValidator; +import haveno.core.trade.HavenoUtils; import lombok.EqualsAndHashCode; import org.jetbrains.annotations.NotNull; @@ -33,9 +36,22 @@ public final class InteracETransferAccount extends PaymentAccount { public static final List SUPPORTED_CURRENCIES = List.of(new TraditionalCurrency("CAD")); + private final InteracETransferValidator interacETransferValidator; + + private static final List INPUT_FIELD_IDS = List.of( + PaymentAccountFormField.FieldId.HOLDER_NAME, + PaymentAccountFormField.FieldId.EMAIL_OR_MOBILE_NR, + PaymentAccountFormField.FieldId.QUESTION, + PaymentAccountFormField.FieldId.ANSWER, + PaymentAccountFormField.FieldId.ACCOUNT_NAME, + PaymentAccountFormField.FieldId.SALT + ); + public InteracETransferAccount() { super(PaymentMethod.INTERAC_E_TRANSFER); setSingleTradeCurrency(SUPPORTED_CURRENCIES.get(0)); + this.interacETransferValidator = HavenoUtils.corePaymentAccountService.interacETransferValidator; + if (interacETransferValidator == null) throw new IllegalArgumentException("InteracETransferValidator cannot be null"); } @Override @@ -50,15 +66,15 @@ public final class InteracETransferAccount extends PaymentAccount { @Override public @NotNull List getInputFieldIds() { - throw new RuntimeException("Not implemented"); + return INPUT_FIELD_IDS; } public void setEmail(String email) { - ((InteracETransferAccountPayload) paymentAccountPayload).setEmail(email); + ((InteracETransferAccountPayload) paymentAccountPayload).setEmailOrMobileNr(email); } public String getEmail() { - return ((InteracETransferAccountPayload) paymentAccountPayload).getEmail(); + return ((InteracETransferAccountPayload) paymentAccountPayload).getEmailOrMobileNr(); } public void setAnswer(String answer) { @@ -84,4 +100,18 @@ public final class InteracETransferAccount extends PaymentAccount { public String getHolderName() { return ((InteracETransferAccountPayload) paymentAccountPayload).getHolderName(); } + + public void validateFormField(PaymentAccountForm form, PaymentAccountFormField.FieldId fieldId, String value) { + switch (fieldId) { + case QUESTION: + processValidationResult(interacETransferValidator.questionValidator.validate(value)); + break; + case ANSWER: + processValidationResult(interacETransferValidator.answerValidator.validate(value)); + break; + default: + super.validateFormField(form, fieldId, value); + } + + } } diff --git a/core/src/main/java/haveno/core/payment/PaymentAccount.java b/core/src/main/java/haveno/core/payment/PaymentAccount.java index 8a7b5f24c1..88e6956915 100644 --- a/core/src/main/java/haveno/core/payment/PaymentAccount.java +++ b/core/src/main/java/haveno/core/payment/PaymentAccount.java @@ -630,7 +630,9 @@ public abstract class PaymentAccount implements PersistablePayload { field.setLabel(Res.get("payment.select.account")); break; case ANSWER: - throw new IllegalArgumentException("Not implemented"); + field.setComponent(PaymentAccountFormField.Component.TEXT); + field.setLabel(Res.get("payment.answer")); + break; case BANK_ACCOUNT_NAME: field.setComponent(PaymentAccountFormField.Component.TEXT); field.setLabel(Res.get("payment.account.owner")); @@ -782,7 +784,9 @@ public abstract class PaymentAccount implements PersistablePayload { case PROMPT_PAY_ID: throw new IllegalArgumentException("Not implemented"); case QUESTION: - throw new IllegalArgumentException("Not implemented"); + field.setComponent(PaymentAccountFormField.Component.TEXT); + field.setLabel(Res.get("payment.secret")); + break; case REQUIREMENTS: throw new IllegalArgumentException("Not implemented"); case SALT: diff --git a/core/src/main/java/haveno/core/payment/payload/InteracETransferAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/InteracETransferAccountPayload.java index 26105e7478..751ecbf045 100644 --- a/core/src/main/java/haveno/core/payment/payload/InteracETransferAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/InteracETransferAccountPayload.java @@ -36,7 +36,7 @@ import java.util.Map; @Getter @Slf4j public final class InteracETransferAccountPayload extends PaymentAccountPayload implements PayloadWithHolderName { - private String email = ""; + private String emailOrMobileNr = ""; private String holderName = ""; private String question = ""; private String answer = ""; @@ -52,7 +52,7 @@ public final class InteracETransferAccountPayload extends PaymentAccountPayload private InteracETransferAccountPayload(String paymentMethod, String id, - String email, + String emailOrMobileNr, String holderName, String question, String answer, @@ -62,7 +62,7 @@ public final class InteracETransferAccountPayload extends PaymentAccountPayload id, maxTradePeriod, excludeFromJsonDataMap); - this.email = email; + this.emailOrMobileNr = emailOrMobileNr; this.holderName = holderName; this.question = question; this.answer = answer; @@ -72,7 +72,7 @@ public final class InteracETransferAccountPayload extends PaymentAccountPayload public Message toProtoMessage() { return getPaymentAccountPayloadBuilder() .setInteracETransferAccountPayload(protobuf.InteracETransferAccountPayload.newBuilder() - .setEmail(email) + .setEmailOrMobileNr(emailOrMobileNr) .setHolderName(holderName) .setQuestion(question) .setAnswer(answer)) @@ -82,7 +82,7 @@ public final class InteracETransferAccountPayload extends PaymentAccountPayload public static InteracETransferAccountPayload fromProto(protobuf.PaymentAccountPayload proto) { return new InteracETransferAccountPayload(proto.getPaymentMethodId(), proto.getId(), - proto.getInteracETransferAccountPayload().getEmail(), + proto.getInteracETransferAccountPayload().getEmailOrMobileNr(), proto.getInteracETransferAccountPayload().getHolderName(), proto.getInteracETransferAccountPayload().getQuestion(), proto.getInteracETransferAccountPayload().getAnswer(), @@ -98,21 +98,21 @@ public final class InteracETransferAccountPayload extends PaymentAccountPayload @Override public String getPaymentDetails() { return Res.get(paymentMethodId) + " - " + Res.getWithCol("payment.account.owner") + " " + holderName + ", " + - Res.get("payment.email") + " " + email + ", " + Res.getWithCol("payment.secret") + " " + + Res.get("payment.email") + " " + emailOrMobileNr + ", " + Res.getWithCol("payment.secret") + " " + question + ", " + Res.getWithCol("payment.answer") + " " + answer; } @Override public String getPaymentDetailsForTradePopup() { return Res.getWithCol("payment.account.owner") + " " + holderName + "\n" + - Res.getWithCol("payment.email") + " " + email + "\n" + + Res.getWithCol("payment.email") + " " + emailOrMobileNr + "\n" + Res.getWithCol("payment.secret") + " " + question + "\n" + Res.getWithCol("payment.answer") + " " + answer; } @Override public byte[] getAgeWitnessInputData() { - return super.getAgeWitnessInputData(ArrayUtils.addAll(email.getBytes(StandardCharsets.UTF_8), + return super.getAgeWitnessInputData(ArrayUtils.addAll(emailOrMobileNr.getBytes(StandardCharsets.UTF_8), ArrayUtils.addAll(question.getBytes(StandardCharsets.UTF_8), answer.getBytes(StandardCharsets.UTF_8)))); } diff --git a/core/src/main/java/haveno/core/payment/payload/PaymentMethod.java b/core/src/main/java/haveno/core/payment/payload/PaymentMethod.java index c4226a97b6..76cd97630e 100644 --- a/core/src/main/java/haveno/core/payment/payload/PaymentMethod.java +++ b/core/src/main/java/haveno/core/payment/payload/PaymentMethod.java @@ -375,7 +375,8 @@ public final class PaymentMethod implements PersistablePayload, Comparable paymentMethodIds.contains(paymentMethod.getId())).collect(Collectors.toList()); } diff --git a/core/src/main/java/haveno/core/trade/HavenoUtils.java b/core/src/main/java/haveno/core/trade/HavenoUtils.java index 32a6d76824..b022cf3cfc 100644 --- a/core/src/main/java/haveno/core/trade/HavenoUtils.java +++ b/core/src/main/java/haveno/core/trade/HavenoUtils.java @@ -31,6 +31,7 @@ import haveno.common.file.FileUtil; import haveno.common.util.Base64; import haveno.common.util.Utilities; import haveno.core.api.CoreNotificationService; +import haveno.core.api.CorePaymentAccountsService; import haveno.core.api.XmrConnectionService; import haveno.core.app.HavenoSetup; import haveno.core.offer.OfferPayload; @@ -132,6 +133,7 @@ public class HavenoUtils { public static XmrConnectionService xmrConnectionService; public static OpenOfferManager openOfferManager; public static CoreNotificationService notificationService; + public static CorePaymentAccountsService corePaymentAccountService; public static Preferences preferences; public static boolean isSeedNode() { diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/InteracETransferForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/InteracETransferForm.java index 8447a1a01a..f57ac5cc09 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/InteracETransferForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/InteracETransferForm.java @@ -44,7 +44,7 @@ public class InteracETransferForm extends PaymentMethodForm { addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.account.owner"), ((InteracETransferAccountPayload) paymentAccountPayload).getHolderName()); addCompactTopLabelTextField(gridPane, gridRow, 1, Res.get("payment.emailOrMobile"), - ((InteracETransferAccountPayload) paymentAccountPayload).getEmail()); + ((InteracETransferAccountPayload) paymentAccountPayload).getEmailOrMobileNr()); addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.secret"), ((InteracETransferAccountPayload) paymentAccountPayload).getQuestion()); addCompactTopLabelTextField(gridPane, gridRow, 1, Res.get("payment.answer"), diff --git a/proto/src/main/proto/pb.proto b/proto/src/main/proto/pb.proto index 46a6361301..e0f05c4ef7 100644 --- a/proto/src/main/proto/pb.proto +++ b/proto/src/main/proto/pb.proto @@ -1047,7 +1047,7 @@ message FasterPaymentsAccountPayload { } message InteracETransferAccountPayload { - string email = 1; + string email_or_mobile_nr = 1; string holder_name = 2; string question = 3; string answer = 4; @@ -1909,6 +1909,7 @@ message PaymentAccountForm { TRANSFERWISE_USD = 23; AMAZON_GIFT_CARD = 24; ACH_TRANSFER = 25; + INTERAC_E_TRANSFER = 26; } FormId id = 1; repeated PaymentAccountFormField fields = 2;