From f72b6c0b0a12f4318e10fb071c0c4d6a7bc75f2e Mon Sep 17 00:00:00 2001 From: jmacxx <47253594+jmacxx@users.noreply.github.com> Date: Wed, 10 Nov 2021 21:26:01 -0600 Subject: [PATCH] Add payment methods Tikkie and TransferWise-USD --- .../core/payment/PaymentAccountFactory.java | 4 + .../java/bisq/core/payment/TikkieAccount.java | 56 +++++++ .../core/payment/TransferwiseUsdAccount.java | 72 +++++++++ .../core/payment/payload/PaymentMethod.java | 8 +- .../payment/payload/TikkieAccountPayload.java | 99 +++++++++++++ .../TransferwiseUsdAccountPayload.java | 109 ++++++++++++++ .../bisq/core/proto/CoreProtoResolver.java | 6 + .../trade/statistics/TradeStatistics3.java | 4 +- .../resources/i18n/displayStrings.properties | 42 ++++++ .../components/paymentmethods/TikkieForm.java | 106 ++++++++++++++ .../paymentmethods/TransferwiseUsdForm.java | 138 ++++++++++++++++++ .../fiataccounts/FiatAccountsView.java | 6 + .../steps/buyer/BuyerStep2View.java | 8 + .../util/validation/IBANValidator.java | 9 ++ proto/src/main/proto/pb.proto | 12 ++ 15 files changed, 677 insertions(+), 2 deletions(-) create mode 100644 core/src/main/java/bisq/core/payment/TikkieAccount.java create mode 100644 core/src/main/java/bisq/core/payment/TransferwiseUsdAccount.java create mode 100644 core/src/main/java/bisq/core/payment/payload/TikkieAccountPayload.java create mode 100644 core/src/main/java/bisq/core/payment/payload/TransferwiseUsdAccountPayload.java create mode 100644 desktop/src/main/java/bisq/desktop/components/paymentmethods/TikkieForm.java create mode 100644 desktop/src/main/java/bisq/desktop/components/paymentmethods/TransferwiseUsdForm.java diff --git a/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java b/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java index 3979eeac096..c570d749bef 100644 --- a/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java +++ b/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java @@ -82,6 +82,8 @@ public static PaymentAccount getPaymentAccount(PaymentMethod paymentMethod) { return new AdvancedCashAccount(); case PaymentMethod.TRANSFERWISE_ID: return new TransferwiseAccount(); + case PaymentMethod.TRANSFERWISE_USD_ID: + return new TransferwiseUsdAccount(); case PaymentMethod.PAYSERA_ID: return new PayseraAccount(); case PaymentMethod.PAXUM_ID: @@ -114,6 +116,8 @@ public static PaymentAccount getPaymentAccount(PaymentMethod paymentMethod) { return new MoneseAccount(); case PaymentMethod.SATISPAY_ID: return new SatispayAccount(); + case PaymentMethod.TIKKIE_ID: + return new TikkieAccount(); case PaymentMethod.VERSE_ID: return new VerseAccount(); case PaymentMethod.STRIKE_ID: diff --git a/core/src/main/java/bisq/core/payment/TikkieAccount.java b/core/src/main/java/bisq/core/payment/TikkieAccount.java new file mode 100644 index 00000000000..813b2a70899 --- /dev/null +++ b/core/src/main/java/bisq/core/payment/TikkieAccount.java @@ -0,0 +1,56 @@ +/* + * 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 . + */ + +package bisq.core.payment; + +import bisq.core.payment.payload.PaymentAccountPayload; +import bisq.core.payment.payload.PaymentMethod; +import bisq.core.payment.payload.TikkieAccountPayload; + +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +public final class TikkieAccount extends CountryBasedPaymentAccount { + public TikkieAccount() { + super(PaymentMethod.TIKKIE); + } + + @Override + protected PaymentAccountPayload createPayload() { + return new TikkieAccountPayload(paymentMethod.getId(), id); + } + + public void setIban(String iban) { + ((TikkieAccountPayload) paymentAccountPayload).setIban(iban); + } + + public String getIban() { + return ((TikkieAccountPayload) paymentAccountPayload).getIban(); + } + + public String getMessageForBuyer() { + return "payment.tikkie.info.buyer"; + } + + public String getMessageForSeller() { + return "payment.tikkie.info.seller"; + } + + public String getMessageForAccountCreation() { + return "payment.tikkie.info.account"; + } +} diff --git a/core/src/main/java/bisq/core/payment/TransferwiseUsdAccount.java b/core/src/main/java/bisq/core/payment/TransferwiseUsdAccount.java new file mode 100644 index 00000000000..ab5e03ab41d --- /dev/null +++ b/core/src/main/java/bisq/core/payment/TransferwiseUsdAccount.java @@ -0,0 +1,72 @@ +/* + * 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 . + */ + +package bisq.core.payment; + +import bisq.core.payment.payload.PaymentAccountPayload; +import bisq.core.payment.payload.PaymentMethod; +import bisq.core.payment.payload.TransferwiseUsdAccountPayload; + +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +public final class TransferwiseUsdAccount extends CountryBasedPaymentAccount { + public TransferwiseUsdAccount() { + super(PaymentMethod.TRANSFERWISE_USD); + } + + @Override + protected PaymentAccountPayload createPayload() { + return new TransferwiseUsdAccountPayload(paymentMethod.getId(), id); + } + + public void setEmail(String email) { + ((TransferwiseUsdAccountPayload) paymentAccountPayload).setEmail(email); + } + + public String getEmail() { + return ((TransferwiseUsdAccountPayload) paymentAccountPayload).getEmail(); + } + + public void setHolderName(String accountId) { + ((TransferwiseUsdAccountPayload) paymentAccountPayload).setHolderName(accountId); + } + + public String getHolderName() { + return ((TransferwiseUsdAccountPayload) paymentAccountPayload).getHolderName(); + } + + public void setBeneficiaryAddress(String address) { + ((TransferwiseUsdAccountPayload) paymentAccountPayload).setBeneficiaryAddress(address); + } + + public String getBeneficiaryAddress() { + return ((TransferwiseUsdAccountPayload) paymentAccountPayload).getBeneficiaryAddress(); + } + + public String getMessageForBuyer() { + return "payment.transferwiseUsd.info.buyer"; + } + + public String getMessageForSeller() { + return "payment.transferwiseUsd.info.seller"; + } + + public String getMessageForAccountCreation() { + return "payment.transferwiseUsd.info.account"; + } +} diff --git a/core/src/main/java/bisq/core/payment/payload/PaymentMethod.java b/core/src/main/java/bisq/core/payment/payload/PaymentMethod.java index ee9f523bf48..59f76e04a82 100644 --- a/core/src/main/java/bisq/core/payment/payload/PaymentMethod.java +++ b/core/src/main/java/bisq/core/payment/payload/PaymentMethod.java @@ -96,6 +96,7 @@ public final class PaymentMethod implements PersistablePayload, Comparable. + */ + +package bisq.core.payment.payload; + +import bisq.core.locale.Res; + +import com.google.protobuf.Message; + +import java.nio.charset.StandardCharsets; + +import java.util.HashMap; +import java.util.Map; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; + +@EqualsAndHashCode(callSuper = true) +@ToString +@Setter +@Getter +@Slf4j +public final class TikkieAccountPayload extends CountryBasedPaymentAccountPayload { + private String iban = ""; + + public TikkieAccountPayload(String paymentMethod, String id) { + super(paymentMethod, id); + } + + private TikkieAccountPayload(String paymentMethod, + String id, + String countryCode, + String iban, + long maxTradePeriod, + Map excludeFromJsonDataMap) { + super(paymentMethod, + id, + countryCode, + maxTradePeriod, + excludeFromJsonDataMap); + + this.iban = iban; + } + + @Override + public Message toProtoMessage() { + protobuf.TikkieAccountPayload.Builder builder = protobuf.TikkieAccountPayload.newBuilder() + .setIban(iban); + final protobuf.CountryBasedPaymentAccountPayload.Builder countryBasedPaymentAccountPayload = getPaymentAccountPayloadBuilder() + .getCountryBasedPaymentAccountPayloadBuilder() + .setTikkieAccountPayload(builder); + return getPaymentAccountPayloadBuilder() + .setCountryBasedPaymentAccountPayload(countryBasedPaymentAccountPayload) + .build(); + } + + public static TikkieAccountPayload fromProto(protobuf.PaymentAccountPayload proto) { + protobuf.CountryBasedPaymentAccountPayload countryBasedPaymentAccountPayload = proto.getCountryBasedPaymentAccountPayload(); + protobuf.TikkieAccountPayload accountPayloadPB = countryBasedPaymentAccountPayload.getTikkieAccountPayload(); + return new TikkieAccountPayload(proto.getPaymentMethodId(), + proto.getId(), + countryBasedPaymentAccountPayload.getCountryCode(), + accountPayloadPB.getIban(), + proto.getMaxTradePeriod(), + new HashMap<>(proto.getExcludeFromJsonDataMap())); + } + + @Override + public String getPaymentDetails() { + return Res.get(paymentMethodId) + " - " + Res.getWithCol("payment.iban") + " " + iban; + } + + @Override + public String getPaymentDetailsForTradePopup() { + return getPaymentDetails(); + } + + @Override + public byte[] getAgeWitnessInputData() { + return super.getAgeWitnessInputData(iban.getBytes(StandardCharsets.UTF_8)); + } +} diff --git a/core/src/main/java/bisq/core/payment/payload/TransferwiseUsdAccountPayload.java b/core/src/main/java/bisq/core/payment/payload/TransferwiseUsdAccountPayload.java new file mode 100644 index 00000000000..71cbb383f08 --- /dev/null +++ b/core/src/main/java/bisq/core/payment/payload/TransferwiseUsdAccountPayload.java @@ -0,0 +1,109 @@ +/* + * 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 . + */ + +package bisq.core.payment.payload; + +import bisq.core.locale.Res; + +import com.google.protobuf.Message; + +import java.nio.charset.StandardCharsets; + +import java.util.HashMap; +import java.util.Map; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; + +@EqualsAndHashCode(callSuper = true) +@ToString +@Setter +@Getter +@Slf4j +public final class TransferwiseUsdAccountPayload extends CountryBasedPaymentAccountPayload { + private String email = ""; + private String holderName = ""; + private String beneficiaryAddress = ""; + + public TransferwiseUsdAccountPayload(String paymentMethod, String id) { + super(paymentMethod, id); + } + + private TransferwiseUsdAccountPayload(String paymentMethod, + String id, + String countryCode, + String email, + String holderName, + String beneficiaryAddress, + long maxTradePeriod, + Map excludeFromJsonDataMap) { + super(paymentMethod, + id, + countryCode, + maxTradePeriod, + excludeFromJsonDataMap); + + this.email = email; + this.holderName = holderName; + this.beneficiaryAddress = beneficiaryAddress; + } + + @Override + public Message toProtoMessage() { + protobuf.TransferwiseUsdAccountPayload.Builder builder = protobuf.TransferwiseUsdAccountPayload.newBuilder() + .setEmail(email) + .setHolderName(holderName) + .setBeneficiaryAddress(beneficiaryAddress); + final protobuf.CountryBasedPaymentAccountPayload.Builder countryBasedPaymentAccountPayload = getPaymentAccountPayloadBuilder() + .getCountryBasedPaymentAccountPayloadBuilder() + .setTransferwiseUsdAccountPayload(builder); + return getPaymentAccountPayloadBuilder() + .setCountryBasedPaymentAccountPayload(countryBasedPaymentAccountPayload) + .build(); + } + + public static TransferwiseUsdAccountPayload fromProto(protobuf.PaymentAccountPayload proto) { + protobuf.CountryBasedPaymentAccountPayload countryBasedPaymentAccountPayload = proto.getCountryBasedPaymentAccountPayload(); + protobuf.TransferwiseUsdAccountPayload accountPayloadPB = countryBasedPaymentAccountPayload.getTransferwiseUsdAccountPayload(); + return new TransferwiseUsdAccountPayload(proto.getPaymentMethodId(), + proto.getId(), + countryBasedPaymentAccountPayload.getCountryCode(), + accountPayloadPB.getEmail(), + accountPayloadPB.getHolderName(), + accountPayloadPB.getBeneficiaryAddress(), + proto.getMaxTradePeriod(), + new HashMap<>(proto.getExcludeFromJsonDataMap())); + } + + @Override + public String getPaymentDetails() { + return Res.get(paymentMethodId) + " - " + Res.getWithCol("payment.account.userName") + " " + holderName; + } + + @Override + public String getPaymentDetailsForTradePopup() { + return getPaymentDetails(); + } + + @Override + public byte[] getAgeWitnessInputData() { + return super.getAgeWitnessInputData(holderName.getBytes(StandardCharsets.UTF_8)); + } +} diff --git a/core/src/main/java/bisq/core/proto/CoreProtoResolver.java b/core/src/main/java/bisq/core/proto/CoreProtoResolver.java index 89d6cd4ed37..7566c43292f 100644 --- a/core/src/main/java/bisq/core/proto/CoreProtoResolver.java +++ b/core/src/main/java/bisq/core/proto/CoreProtoResolver.java @@ -67,7 +67,9 @@ import bisq.core.payment.payload.StrikeAccountPayload; import bisq.core.payment.payload.SwiftAccountPayload; import bisq.core.payment.payload.SwishAccountPayload; +import bisq.core.payment.payload.TikkieAccountPayload; import bisq.core.payment.payload.TransferwiseAccountPayload; +import bisq.core.payment.payload.TransferwiseUsdAccountPayload; import bisq.core.payment.payload.USPostalMoneyOrderAccountPayload; import bisq.core.payment.payload.UpholdAccountPayload; import bisq.core.payment.payload.UpiAccountPayload; @@ -144,8 +146,12 @@ public PaymentAccountPayload fromProto(protobuf.PaymentAccountPayload proto) { return PixAccountPayload.fromProto(proto); case SATISPAY_ACCOUNT_PAYLOAD: return SatispayAccountPayload.fromProto(proto); + case TIKKIE_ACCOUNT_PAYLOAD: + return TikkieAccountPayload.fromProto(proto); case STRIKE_ACCOUNT_PAYLOAD: return StrikeAccountPayload.fromProto(proto); + case TRANSFERWISE_USD_ACCOUNT_PAYLOAD: + return TransferwiseUsdAccountPayload.fromProto(proto); case IFSC_BASED_ACCOUNT_PAYLOAD: final protobuf.IfscBasedAccountPayload.MessageCase messageCaseIfsc = proto.getCountryBasedPaymentAccountPayload().getIfscBasedAccountPayload().getMessageCase(); switch (messageCaseIfsc) { diff --git a/core/src/main/java/bisq/core/trade/statistics/TradeStatistics3.java b/core/src/main/java/bisq/core/trade/statistics/TradeStatistics3.java index bac91b3b28d..f98e93db019 100644 --- a/core/src/main/java/bisq/core/trade/statistics/TradeStatistics3.java +++ b/core/src/main/java/bisq/core/trade/statistics/TradeStatistics3.java @@ -184,7 +184,9 @@ private enum PaymentMethodMapper { MONESE, SATISPAY, VERSE, - STRIKE + STRIKE, + TIKKIE, + TRANSFERWISE_USD } @Getter diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index c0102446e7b..8de295d2642 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -3365,6 +3365,7 @@ payment.account.owner=Account owner full name payment.account.fullName=Full name (first, middle, last) payment.account.state=State/Province/Region payment.account.city=City +payment.account.address=Address payment.bank.country=Country of bank payment.account.name.email=Account owner full name / email payment.account.name.emailAndHolderId=Account owner full name / email / {0} @@ -3417,6 +3418,7 @@ payment.swift.phone.beneficiary=Beneficiary phone number payment.swift.account=Account No. (or IBAN) payment.swift.use.intermediary=Use Intermediary Bank payment.swift.showPaymentInfo=Show Payment Information... +payment.transferwiseUsd.address=Account owner address (must be US-based, consider using bank address) payment.amazon.site=Buy giftcard at payment.ask=Ask in Trader Chat @@ -3461,6 +3463,8 @@ payment.bankIdOptional=Bank ID (BIC/SWIFT) (optional) payment.branchNr=Branch no. payment.branchNrOptional=Branch no. (optional) payment.accountNrLabel=Account no. (IBAN) +payment.iban=IBAN +payment.tikkie.iban=IBAN used for Bisq trading on Tikkie payment.accountType=Account type payment.checking=Checking payment.savings=Savings @@ -3733,6 +3737,26 @@ Satispay account limits are individually set. If you want to trade increased amo support to increase your limits. Traders on Bisq should be aware of their limits. If you trade over the above limits \ your trade might be cancelled and there could be a penalty. +payment.tikkie.info.account=To use Tikkie you need a bank account (IBAN) in The Netherlands and to be registered for the service.\n\n\ +When you send a Tikkie payment request to an individual person you can ask to receive a maximum of €750 per Tikkie \ + request. The maximum amount you can request within 24 hours is €2,500 per Tikkie account.\n\n\ +Each bank however may establish its own limits, within these limits, for its clients.\n\n\ +Traders on Bisq should be aware of their limits. If you trade over the above limits your trade might be cancelled and there could be a penalty. +payment.tikkie.info.buyer=Please request a payment link from the BTC Seller in trader chat. Once the BTC Seller has \ + sent you a payment link that matches the correct amount for the trade please proceed to payment.\n\n\ +When the BTC Seller requests a Tikkie payment the maximum they can ask to receive is €750 per Tikkie request. If the \ + trade is over that amount the BTC Seller will have to sent multiple requests to total the trade amount. The maximum \ + you can request in a day is €2,500.\n\n\ +Each bank however may establish its own limits, within these limits, for its clients.\n\n\ +Traders on Bisq should be aware of their limits. If you trade over the above limits your trade might be cancelled and there could be a penalty. +payment.tikkie.info.seller=Please send a payment link to the BTC Seller in trader chat. Once the BTC \ + Buyer has sent you payment please check their IBAN detail match the details they have in Bisq.\n\n\ +When the BTC Seller requests a Tikkie payment the maximum they can ask to receive is €750 per Tikkie request. If the \ + trade is over that amount the BTC Seller will have to sent multiple requests to total the trade amount. The maximum \ + you can request in a day is €2,500.\n\n\ +Each bank however may establish its own limits, within these limits, for its clients.\n\n\ +Traders on Bisq should be aware of their limits. If you trade over the above limits your trade might be cancelled and there could be a penalty. + payment.verse.info.account=Verse is a multiple currency payment method that can send and receive payment in EUR, SEK, HUF, DKK, PLN.\n\n\ When setting up your Verse account in Bisq please make sure to include the username that matches your username in your \ Verse account. This will ensure that when you send funds they show from the correct account and when you receive \ @@ -3766,6 +3790,16 @@ payment.strike.info.seller=Please make sure your payment is received from the BT The maximum trade size is $1,000 per payment.\n\n\ If you trade over the above limits your trade might be cancelled and there could be a penalty. +payment.transferwiseUsd.info.account=Due US banking regulation, sending and receiving USD payments has more restrictions \ + than most other currencies. For this reason USD was not added to Bisq TransferWise payment method.\n\n\ +The TransferWise-USD payment method allows Bisq users to trade in USD.\n\n\ +Anyone with a Wise, formally TransferWise account, can add TransferWise-USD as a payment method in Bisq. This will \ + allow them to buy and sell BTC with USD.\n\n\ +When trading on Bisq BTC Buyers should not use any reference for reason for payment. If reason for payment is required \ + they should only use the full name of the TransferWise-USD account owner. +payment.transferwiseUsd.info.buyer=Please send payment only to the email address in the BTC Seller's Bisq TransferWise-USD account. +payment.transferwiseUsd.info.seller=Please check that the payment received matches the BTC Buyer's name of the TransferWise-USD account in Bisq. + payment.usPostalMoneyOrder.info=Trading using US Postal Money Orders (USPMO) on Bisq requires that you understand the following:\n\ \n\ - BTC buyers must write the BTC Seller’s name in both the Payer and the Payee’s fields & take a high-resolution photo of the USPMO and envelope with proof of tracking before sending.\n\ @@ -3928,6 +3962,8 @@ ADVANCED_CASH=Advanced Cash # suppress inspection "UnusedProperty" TRANSFERWISE=TransferWise # suppress inspection "UnusedProperty" +TRANSFERWISE_USD=TransferWise-USD +# suppress inspection "UnusedProperty" PAYSERA=Paysera # suppress inspection "UnusedProperty" PAXUM=Paxum @@ -3960,6 +3996,8 @@ MONESE=Monese # suppress inspection "UnusedProperty" SATISPAY=Satispay # suppress inspection "UnusedProperty" +TIKKIE=Tikkie +# suppress inspection "UnusedProperty" VERSE=Verse # suppress inspection "UnusedProperty" STRIKE=Strike @@ -4016,6 +4054,8 @@ ADVANCED_CASH_SHORT=Advanced Cash # suppress inspection "UnusedProperty" TRANSFERWISE_SHORT=TransferWise # suppress inspection "UnusedProperty" +TRANSFERWISE_USD_SHORT=TransferWise-USD +# suppress inspection "UnusedProperty" PAYSERA_SHORT=Paysera # suppress inspection "UnusedProperty" PAXUM_SHORT=Paxum @@ -4048,6 +4088,8 @@ MONESE_SHORT=Monese # suppress inspection "UnusedProperty" SATISPAY_SHORT=Satispay # suppress inspection "UnusedProperty" +TIKKIE_SHORT=Tikkie +# suppress inspection "UnusedProperty" VERSE_SHORT=Verse # suppress inspection "UnusedProperty" STRIKE_SHORT=Strike diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/TikkieForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/TikkieForm.java new file mode 100644 index 00000000000..5bed80dae7a --- /dev/null +++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/TikkieForm.java @@ -0,0 +1,106 @@ +/* + * 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 . + */ + +package bisq.desktop.components.paymentmethods; + +import bisq.desktop.components.InputTextField; +import bisq.desktop.util.FormBuilder; +import bisq.desktop.util.Layout; +import bisq.desktop.util.validation.IBANValidator; + +import bisq.core.account.witness.AccountAgeWitnessService; +import bisq.core.locale.CountryUtil; +import bisq.core.locale.FiatCurrency; +import bisq.core.locale.Res; +import bisq.core.payment.PaymentAccount; +import bisq.core.payment.TikkieAccount; +import bisq.core.payment.payload.PaymentAccountPayload; +import bisq.core.payment.payload.TikkieAccountPayload; +import bisq.core.util.coin.CoinFormatter; +import bisq.core.util.validation.InputValidator; + +import javafx.scene.layout.GridPane; + +import static bisq.desktop.util.FormBuilder.addCompactTopLabelTextField; +import static bisq.desktop.util.FormBuilder.addCompactTopLabelTextFieldWithCopyIcon; +import static bisq.desktop.util.FormBuilder.addTopLabelTextField; + +public class TikkieForm extends PaymentMethodForm { + private final TikkieAccount account; + private InputTextField ibanField; + private final IBANValidator ibanValidator = new IBANValidator("NL"); + + public static int addFormForBuyer(GridPane gridPane, int gridRow, + PaymentAccountPayload paymentAccountPayload) { + addCompactTopLabelTextFieldWithCopyIcon(gridPane, ++gridRow, 0, Res.get("payment.tikkie.iban"), + ((TikkieAccountPayload) paymentAccountPayload).getIban()); + return gridRow; + } + + public TikkieForm(PaymentAccount paymentAccount, AccountAgeWitnessService accountAgeWitnessService, + InputValidator inputValidator, GridPane gridPane, + int gridRow, CoinFormatter formatter) { + super(paymentAccount, accountAgeWitnessService, inputValidator, gridPane, gridRow, formatter); + this.account = (TikkieAccount) paymentAccount; + } + + @Override + public void addFormForAddAccount() { + // this payment method is only for Netherlands/EUR + account.setSingleTradeCurrency(new FiatCurrency("EUR")); + CountryUtil.findCountryByCode("NL").ifPresent(c -> account.setCountry(c)); + + gridRowFrom = gridRow + 1; + + ibanField = FormBuilder.addInputTextField(gridPane, ++gridRow, Res.get("payment.tikkie.iban")); + ibanField.setValidator(ibanValidator); + ibanField.textProperty().addListener((ov, oldValue, newValue) -> { + account.setIban(newValue.trim()); + updateFromInputs(); + }); + + addTopLabelTextField(gridPane, ++gridRow, Res.get("shared.currency"), account.getSingleTradeCurrency().getNameAndCode()); + addTopLabelTextField(gridPane, ++gridRow, Res.get("shared.country"), account.getCountry().name); + addLimitations(false); + addAccountNameTextFieldWithAutoFillToggleButton(); + } + + @Override + protected void autoFillNameTextField() { + setAccountNameWithString(ibanField.getText()); + } + + @Override + public void addFormForDisplayAccount() { + gridRowFrom = gridRow; + addTopLabelTextField(gridPane, gridRow, Res.get("payment.account.name"), + account.getAccountName(), Layout.FIRST_ROW_AND_GROUP_DISTANCE); + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.paymentMethod"), + Res.get(account.getPaymentMethod().getId())); + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.tikkie.iban"), account.getIban()) + .second.setMouseTransparent(false); + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.currency"), account.getSingleTradeCurrency().getNameAndCode()); + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.country"), account.getCountry().name); + addLimitations(true); + } + + @Override + public void updateAllInputsValid() { + allInputsValid.set(isAccountNameValid() + && ibanValidator.validate(account.getIban()).isValid); + } +} diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/TransferwiseUsdForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/TransferwiseUsdForm.java new file mode 100644 index 00000000000..69a5e9183e6 --- /dev/null +++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/TransferwiseUsdForm.java @@ -0,0 +1,138 @@ +/* + * 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 . + */ + +package bisq.desktop.components.paymentmethods; + +import bisq.desktop.components.InputTextField; +import bisq.desktop.util.Layout; +import bisq.desktop.util.validation.EmailValidator; +import bisq.desktop.util.validation.LengthValidator; + +import bisq.core.account.witness.AccountAgeWitnessService; +import bisq.core.locale.CountryUtil; +import bisq.core.locale.FiatCurrency; +import bisq.core.locale.Res; +import bisq.core.payment.PaymentAccount; +import bisq.core.payment.TransferwiseUsdAccount; +import bisq.core.payment.payload.PaymentAccountPayload; +import bisq.core.payment.payload.TransferwiseUsdAccountPayload; +import bisq.core.util.coin.CoinFormatter; +import bisq.core.util.validation.InputValidator; + +import javafx.scene.control.TextArea; +import javafx.scene.layout.GridPane; + +import static bisq.common.util.Utilities.cleanString; +import static bisq.desktop.util.FormBuilder.*; + +public class TransferwiseUsdForm extends PaymentMethodForm { + private final TransferwiseUsdAccount account; + private final LengthValidator addressValidator = new LengthValidator(0, 100); + private EmailValidator emailValidator = new EmailValidator(); + + public static int addFormForBuyer(GridPane gridPane, int gridRow, + PaymentAccountPayload paymentAccountPayload) { + + addTopLabelTextFieldWithCopyIcon(gridPane, gridRow, 1, Res.get("payment.account.owner"), + ((TransferwiseUsdAccountPayload) paymentAccountPayload).getHolderName(), + Layout.COMPACT_FIRST_ROW_AND_GROUP_DISTANCE); + + addCompactTopLabelTextFieldWithCopyIcon(gridPane, ++gridRow, 1, Res.get("payment.email"), + ((TransferwiseUsdAccountPayload) paymentAccountPayload).getEmail()); + + String address = ((TransferwiseUsdAccountPayload) paymentAccountPayload).getBeneficiaryAddress(); + if (address.length() > 0) { + TextArea textAddress = addCompactTopLabelTextArea(gridPane, gridRow, 0, Res.get("payment.account.address"), "").second; + textAddress.setMinHeight(70); + textAddress.setEditable(false); + textAddress.setText(address); + } + + return gridRow; + } + + public TransferwiseUsdForm(PaymentAccount paymentAccount, AccountAgeWitnessService accountAgeWitnessService, + InputValidator inputValidator, GridPane gridPane, + int gridRow, CoinFormatter formatter) { + super(paymentAccount, accountAgeWitnessService, inputValidator, gridPane, gridRow, formatter); + this.account = (TransferwiseUsdAccount) paymentAccount; + } + + @Override + public void addFormForAddAccount() { + // this payment method is currently restricted to United States/USD + account.setSingleTradeCurrency(new FiatCurrency("USD")); + CountryUtil.findCountryByCode("US").ifPresent(c -> account.setCountry(c)); + + gridRowFrom = gridRow + 1; + + InputTextField emailField = addInputTextField(gridPane, ++gridRow, Res.get("payment.email")); + emailField.setValidator(emailValidator); + emailField.textProperty().addListener((ov, oldValue, newValue) -> { + account.setEmail(newValue.trim()); + updateFromInputs(); + }); + + InputTextField holderNameField = addInputTextField(gridPane, ++gridRow, Res.get("payment.account.owner")); + holderNameField.setValidator(inputValidator); + holderNameField.textProperty().addListener((ov, oldValue, newValue) -> { + account.setHolderName(newValue.trim()); + updateFromInputs(); + }); + + TextArea addressTextArea = addTopLabelTextArea(gridPane, ++gridRow, Res.get("payment.transferwiseUsd.address"), Res.get("payment.transferwiseUsd.address")).second; + addressTextArea.setMinHeight(70); + addressTextArea.textProperty().addListener((ov, oldValue, newValue) -> { + account.setBeneficiaryAddress(newValue.trim()); + updateFromInputs(); + }); + + addTopLabelTextField(gridPane, ++gridRow, Res.get("shared.currency"), account.getSingleTradeCurrency().getNameAndCode()); + addTopLabelTextField(gridPane, ++gridRow, Res.get("shared.country"), account.getCountry().name); + addLimitations(false); + addAccountNameTextFieldWithAutoFillToggleButton(); + } + + @Override + protected void autoFillNameTextField() { + setAccountNameWithString(account.getHolderName()); + } + + @Override + public void addFormForDisplayAccount() { + gridRowFrom = gridRow; + addTopLabelTextField(gridPane, gridRow, Res.get("payment.account.name"), + account.getAccountName(), Layout.FIRST_ROW_AND_GROUP_DISTANCE); + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.paymentMethod"), + Res.get(account.getPaymentMethod().getId())); + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.email"), account.getEmail()); + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.account.owner"), account.getHolderName()); + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.account.address"), cleanString(account.getBeneficiaryAddress())); + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.currency"), account.getSingleTradeCurrency().getNameAndCode()); + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.country"), account.getCountry().name); + addLimitations(true); + } + + @Override + public void updateAllInputsValid() { + allInputsValid.set(isAccountNameValid() + && emailValidator.validate(account.getEmail()).isValid + && inputValidator.validate(account.getHolderName()).isValid + && addressValidator.validate(account.getBeneficiaryAddress()).isValid + ); + } +} diff --git a/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsView.java b/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsView.java index 4742864e446..178c63084bd 100644 --- a/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsView.java +++ b/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsView.java @@ -60,7 +60,9 @@ import bisq.desktop.components.paymentmethods.StrikeForm; import bisq.desktop.components.paymentmethods.SwiftForm; import bisq.desktop.components.paymentmethods.SwishForm; +import bisq.desktop.components.paymentmethods.TikkieForm; import bisq.desktop.components.paymentmethods.TransferwiseForm; +import bisq.desktop.components.paymentmethods.TransferwiseUsdForm; import bisq.desktop.components.paymentmethods.USPostalMoneyOrderForm; import bisq.desktop.components.paymentmethods.UpholdForm; import bisq.desktop.components.paymentmethods.UpiForm; @@ -555,6 +557,8 @@ private PaymentMethodForm getPaymentMethodForm(PaymentMethod paymentMethod, Paym return new AdvancedCashForm(paymentAccount, accountAgeWitnessService, advancedCashValidator, inputValidator, root, gridRow, formatter); case PaymentMethod.TRANSFERWISE_ID: return new TransferwiseForm(paymentAccount, accountAgeWitnessService, transferwiseValidator, inputValidator, root, gridRow, formatter); + case PaymentMethod.TRANSFERWISE_USD_ID: + return new TransferwiseUsdForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter); case PaymentMethod.PAYSERA_ID: return new PayseraForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter); case PaymentMethod.PAXUM_ID: @@ -585,6 +589,8 @@ private PaymentMethodForm getPaymentMethodForm(PaymentMethod paymentMethod, Paym return new MoneseForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter); case PaymentMethod.SATISPAY_ID: return new SatispayForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter); + case PaymentMethod.TIKKIE_ID: + return new TikkieForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter); case PaymentMethod.VERSE_ID: return new VerseForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter); case PaymentMethod.STRIKE_ID: diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java index a4bbeb83770..a2ee010eec7 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java @@ -61,7 +61,9 @@ import bisq.desktop.components.paymentmethods.StrikeForm; import bisq.desktop.components.paymentmethods.SwiftForm; import bisq.desktop.components.paymentmethods.SwishForm; +import bisq.desktop.components.paymentmethods.TikkieForm; import bisq.desktop.components.paymentmethods.TransferwiseForm; +import bisq.desktop.components.paymentmethods.TransferwiseUsdForm; import bisq.desktop.components.paymentmethods.USPostalMoneyOrderForm; import bisq.desktop.components.paymentmethods.UpholdForm; import bisq.desktop.components.paymentmethods.UpiForm; @@ -338,6 +340,9 @@ protected void addContent() { case PaymentMethod.TRANSFERWISE_ID: gridRow = TransferwiseForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); break; + case PaymentMethod.TRANSFERWISE_USD_ID: + gridRow = TransferwiseUsdForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); + break; case PaymentMethod.PAYSERA_ID: gridRow = PayseraForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); break; @@ -383,6 +388,9 @@ protected void addContent() { case PaymentMethod.SATISPAY_ID: gridRow = SatispayForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); break; + case PaymentMethod.TIKKIE_ID: + gridRow = TikkieForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); + break; case PaymentMethod.VERSE_ID: gridRow = VerseForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); break; diff --git a/desktop/src/main/java/bisq/desktop/util/validation/IBANValidator.java b/desktop/src/main/java/bisq/desktop/util/validation/IBANValidator.java index e202ffee3ac..63cc20c2c11 100644 --- a/desktop/src/main/java/bisq/desktop/util/validation/IBANValidator.java +++ b/desktop/src/main/java/bisq/desktop/util/validation/IBANValidator.java @@ -27,9 +27,16 @@ // TODO Does not yet recognize special letters like ä, ö, ü, å, ... as invalid characters public final class IBANValidator extends InputValidator { + private String restrictToCountry = ""; /////////////////////////////////////////////////////////////////////////////////////////// // Public methods /////////////////////////////////////////////////////////////////////////////////////////// + public IBANValidator() { + } + + public IBANValidator(String restrictToCountry) { + this.restrictToCountry = restrictToCountry; + } @Override public ValidationResult validate(String input) { @@ -45,6 +52,8 @@ public ValidationResult validate(String input) { // check if country code is letters and checksum numeric if (!(Character.isLetter(input.charAt(0)) && Character.isLetter(input.charAt(1)))) return new ValidationResult(false, Res.get("validation.iban.invalidCountryCode")); + if (restrictToCountry.length() > 0 && !restrictToCountry.equals(input.substring(0, 2))) + return new ValidationResult(false, Res.get("validation.iban.invalidCountryCode")); if (!(Character.isDigit(input.charAt(2)) && Character.isDigit(input.charAt(3)))) return new ValidationResult(false, Res.get("validation.iban.checkSumNotNumeric")); diff --git a/proto/src/main/proto/pb.proto b/proto/src/main/proto/pb.proto index a728e495fbe..255cc52c3aa 100644 --- a/proto/src/main/proto/pb.proto +++ b/proto/src/main/proto/pb.proto @@ -1133,6 +1133,8 @@ message CountryBasedPaymentAccountPayload { PixAccountPayload pix_account_payload = 14; SatispayAccountPayload satispay_account_payload = 15; StrikeAccountPayload strike_account_payload = 16; + TikkieAccountPayload tikkie_account_payload = 17; + TransferwiseUsdAccountPayload transferwise_usd_account_payload = 18; } } @@ -1354,6 +1356,12 @@ message TransferwiseAccountPayload { string email = 1; } +message TransferwiseUsdAccountPayload { + string email = 1; + string holder_name = 2; + string beneficiary_address = 3; +} + message PayseraAccountPayload { string email = 1; } @@ -1396,6 +1404,10 @@ message StrikeAccountPayload { string holder_name = 1; } +message TikkieAccountPayload { + string iban = 1; +} + message VerseAccountPayload { string holder_name = 1; }