diff --git a/common/src/main/java/bisq/common/util/Utilities.java b/common/src/main/java/bisq/common/util/Utilities.java
index 3d530b918d2..d0ef2304e35 100644
--- a/common/src/main/java/bisq/common/util/Utilities.java
+++ b/common/src/main/java/bisq/common/util/Utilities.java
@@ -591,4 +591,8 @@ public static String formatDurationAsWords(long durationMillis) {
}
return result;
}
+
+ public static String cleanString(String string) {
+ return string.replaceAll("[\\t\\n\\r]+", " ");
+ }
}
diff --git a/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java b/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java
index 345702623e6..f6c528a8ae5 100644
--- a/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java
+++ b/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java
@@ -92,6 +92,8 @@ public static PaymentAccount getPaymentAccount(PaymentMethod paymentMethod) {
return new InstantCryptoCurrencyAccount();
case PaymentMethod.CAPITUAL_ID:
return new CapitualAccount();
+ case PaymentMethod.SWIFT_ID:
+ return new SwiftAccount();
// Cannot be deleted as it would break old trade history entries
case PaymentMethod.OK_PAY_ID:
diff --git a/core/src/main/java/bisq/core/payment/SwiftAccount.java b/core/src/main/java/bisq/core/payment/SwiftAccount.java
new file mode 100644
index 00000000000..dd932622b4f
--- /dev/null
+++ b/core/src/main/java/bisq/core/payment/SwiftAccount.java
@@ -0,0 +1,54 @@
+/*
+ * 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.locale.CurrencyUtil;
+import bisq.core.locale.FiatCurrency;
+import bisq.core.locale.TradeCurrency;
+import bisq.core.payment.payload.SwiftAccountPayload;
+import bisq.core.payment.payload.PaymentAccountPayload;
+import bisq.core.payment.payload.PaymentMethod;
+
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+public final class SwiftAccount extends PaymentAccount {
+ public SwiftAccount() {
+ super(PaymentMethod.SWIFT);
+ }
+
+ @Override
+ protected PaymentAccountPayload createPayload() {
+ return new SwiftAccountPayload(paymentMethod.getId(), id);
+ }
+
+ public SwiftAccountPayload getPayload() {
+ return ((SwiftAccountPayload) this.paymentAccountPayload);
+ }
+
+ public void selectAllTradeCurrencies() {
+ List currencyCodesSorted = CurrencyUtil.getAllSortedFiatCurrencies().stream()
+ .sorted(Comparator.comparing(TradeCurrency::getCode))
+ .collect(Collectors.toList());
+ tradeCurrencies.addAll(currencyCodesSorted);
+ }
+}
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 dd6fe31db01..91721e06562 100644
--- a/core/src/main/java/bisq/core/payment/payload/PaymentMethod.java
+++ b/core/src/main/java/bisq/core/payment/payload/PaymentMethod.java
@@ -102,6 +102,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 SwiftAccountPayload extends PaymentAccountPayload {
+ // payload data elements
+ private String bankSwiftCode = "";
+ private String bankCountryCode = "";
+ private String bankName = "";
+ private String bankBranch = "";
+ private String bankAddress = "";
+ private String beneficiaryName = "";
+ private String beneficiaryAccountNr = "";
+ private String beneficiaryAddress = "";
+ private String beneficiaryCity = "";
+ private String beneficiaryPhone = "";
+ private String specialInstructions = "";
+ private String intermediarySwiftCode = "";
+ private String intermediaryCountryCode = "";
+ private String intermediaryName = "";
+ private String intermediaryBranch = "";
+ private String intermediaryAddress = "";
+
+ // constants
+ public static final String BANKPOSTFIX = ".bank";
+ public static final String INTERMEDIARYPOSTFIX = ".intermediary";
+ public static final String BENEFICIARYPOSTFIX = ".beneficiary";
+ public static final String SWIFT_CODE = "payment.swift.swiftCode";
+ public static final String COUNTRY = "payment.swift.country";
+ public static final String SWIFT_ACCOUNT = "payment.swift.account";
+ public static final String SNAME = "payment.swift.name";
+ public static final String BRANCH = "payment.swift.branch";
+ public static final String ADDRESS = "payment.swift.address";
+ public static final String PHONE = "payment.swift.phone";
+
+ public SwiftAccountPayload(String paymentMethod, String id) {
+ super(paymentMethod, id);
+ }
+
+ private SwiftAccountPayload(String paymentMethod,
+ String id,
+ String bankSwiftCode,
+ String bankCountryCode,
+ String bankName,
+ String bankBranch,
+ String bankAddress,
+ String beneficiaryName,
+ String beneficiaryAccountNr,
+ String beneficiaryAddress,
+ String beneficiaryCity,
+ String beneficiaryPhone,
+ String specialInstructions,
+ String intermediarySwiftCode,
+ String intermediaryCountryCode,
+ String intermediaryName,
+ String intermediaryBranch,
+ String intermediaryAddress,
+ long maxTradePeriod,
+ Map excludeFromJsonDataMap) {
+ super(paymentMethod,
+ id,
+ maxTradePeriod,
+ excludeFromJsonDataMap);
+
+ this.bankSwiftCode = bankSwiftCode;
+ this.bankCountryCode = bankCountryCode;
+ this.bankName = bankName;
+ this.bankBranch = bankBranch;
+ this.bankAddress = bankAddress;
+ this.beneficiaryName = beneficiaryName;
+ this.beneficiaryAccountNr = beneficiaryAccountNr;
+ this.beneficiaryAddress = beneficiaryAddress;
+ this.beneficiaryCity = beneficiaryCity;
+ this.beneficiaryPhone = beneficiaryPhone;
+ this.specialInstructions = specialInstructions;
+ this.intermediarySwiftCode = intermediarySwiftCode;
+ this.intermediaryCountryCode = intermediaryCountryCode;
+ this.intermediaryName = intermediaryName;
+ this.intermediaryBranch = intermediaryBranch;
+ this.intermediaryAddress = intermediaryAddress;
+ }
+
+ @Override
+ public Message toProtoMessage() {
+ return getPaymentAccountPayloadBuilder()
+ .setSwiftAccountPayload(protobuf.SwiftAccountPayload.newBuilder()
+ .setBankSwiftCode(bankSwiftCode)
+ .setBankCountryCode(bankCountryCode)
+ .setBankName(bankName)
+ .setBankBranch(bankBranch)
+ .setBankAddress(bankAddress)
+ .setBeneficiaryName(beneficiaryName)
+ .setBeneficiaryAccountNr(beneficiaryAccountNr)
+ .setBeneficiaryAddress(beneficiaryAddress)
+ .setBeneficiaryCity(beneficiaryCity)
+ .setBeneficiaryPhone(beneficiaryPhone)
+ .setSpecialInstructions(specialInstructions)
+ .setIntermediarySwiftCode(intermediarySwiftCode)
+ .setIntermediaryCountryCode(intermediaryCountryCode)
+ .setIntermediaryName(intermediaryName)
+ .setIntermediaryBranch(intermediaryBranch)
+ .setIntermediaryAddress(intermediaryAddress)
+ )
+ .build();
+ }
+
+ public static SwiftAccountPayload fromProto(protobuf.PaymentAccountPayload proto) {
+ protobuf.SwiftAccountPayload x = proto.getSwiftAccountPayload();
+ return new SwiftAccountPayload(proto.getPaymentMethodId(),
+ proto.getId(),
+ x.getBankSwiftCode(),
+ x.getBankCountryCode(),
+ x.getBankName(),
+ x.getBankBranch(),
+ x.getBankAddress(),
+ x.getBeneficiaryName(),
+ x.getBeneficiaryAccountNr(),
+ x.getBeneficiaryAddress(),
+ x.getBeneficiaryCity(),
+ x.getBeneficiaryPhone(),
+ x.getSpecialInstructions(),
+ x.getIntermediarySwiftCode(),
+ x.getIntermediaryCountryCode(),
+ x.getIntermediaryName(),
+ x.getIntermediaryBranch(),
+ x.getIntermediaryAddress(),
+ proto.getMaxTradePeriod(),
+ new HashMap<>(proto.getExcludeFromJsonDataMap()));
+ }
+
+ @Override
+ public String getPaymentDetails() {
+ return Res.get(paymentMethodId) + " - " + beneficiaryName;
+ }
+
+ @Override
+ public String getPaymentDetailsForTradePopup() {
+ return getPaymentDetails();
+ }
+
+ @Override
+ public byte[] getAgeWitnessInputData() {
+ return super.getAgeWitnessInputData(beneficiaryAccountNr.getBytes(StandardCharsets.UTF_8));
+ }
+
+ public boolean usesIntermediaryBank() {
+ return (intermediarySwiftCode != null && intermediarySwiftCode.length() > 0);
+ }
+}
diff --git a/core/src/main/java/bisq/core/proto/CoreProtoResolver.java b/core/src/main/java/bisq/core/proto/CoreProtoResolver.java
index d51503a15c8..2c70420c4e9 100644
--- a/core/src/main/java/bisq/core/proto/CoreProtoResolver.java
+++ b/core/src/main/java/bisq/core/proto/CoreProtoResolver.java
@@ -53,6 +53,7 @@
import bisq.core.payment.payload.SepaAccountPayload;
import bisq.core.payment.payload.SepaInstantAccountPayload;
import bisq.core.payment.payload.SpecificBanksAccountPayload;
+import bisq.core.payment.payload.SwiftAccountPayload;
import bisq.core.payment.payload.SwishAccountPayload;
import bisq.core.payment.payload.TransferwiseAccountPayload;
import bisq.core.payment.payload.USPostalMoneyOrderAccountPayload;
@@ -168,6 +169,8 @@ public PaymentAccountPayload fromProto(protobuf.PaymentAccountPayload proto) {
return InstantCryptoCurrencyPayload.fromProto(proto);
case CAPITUAL_ACCOUNT_PAYLOAD:
return CapitualAccountPayload.fromProto(proto);
+ case SWIFT_ACCOUNT_PAYLOAD:
+ return SwiftAccountPayload.fromProto(proto);
// Cannot be deleted as it would break old trade history entries
case O_K_PAY_ACCOUNT_PAYLOAD:
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 fcc57d6f89d..6f381b2d6ed 100644
--- a/core/src/main/java/bisq/core/trade/statistics/TradeStatistics3.java
+++ b/core/src/main/java/bisq/core/trade/statistics/TradeStatistics3.java
@@ -155,7 +155,8 @@ private enum PaymentMethodMapper {
CASH_BY_MAIL,
CAPITUAL,
PAYSERA,
- PAXUM
+ PAXUM,
+ SWIFT
}
@Getter
diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties
index f1452c309f0..0fedd67a81c 100644
--- a/core/src/main/resources/i18n/displayStrings.properties
+++ b/core/src/main/resources/i18n/displayStrings.properties
@@ -660,6 +660,9 @@ portfolio.pending.step2_buyer.refTextWarn=Important: when making the payment, le
# suppress inspection "TrailingSpacesInProperty"
portfolio.pending.step2_buyer.fees=If your bank charges you any fees to make the transfer, you are responsible for paying those fees.
# suppress inspection "TrailingSpacesInProperty"
+portfolio.pending.step2_buyer.fees.swift=Make sure to use the SHA (shared fee model) to send the SWIFT payment. \
+ See more details at [HYPERLINK:https://bisq.wiki/SWIFT#Use_the_correct_fee_option].
+# suppress inspection "TrailingSpacesInProperty"
portfolio.pending.step2_buyer.altcoin=Please transfer from your external {0} wallet\n{1} to the BTC seller.\n\n
# suppress inspection "TrailingSpacesInProperty"
portfolio.pending.step2_buyer.cash=Please go to a bank and pay {0} to the BTC seller.\n\n
@@ -3280,6 +3283,27 @@ payment.secret=Secret question
payment.answer=Answer
payment.wallet=Wallet ID
payment.capitual.cap=CAP Code
+
+# suppress inspection "UnusedProperty"
+payment.swift.headline=International SWIFT Wire Transfer
+payment.swift.title.bank=Receiving Bank
+payment.swift.title.intermediary=Intermediary Bank (click to expand)
+payment.swift.country.bank=Receiving Bank Country
+payment.swift.country.intermediary=Intermediary Bank Country
+payment.swift.swiftCode.bank=Receiving Bank SWIFT Code
+payment.swift.swiftCode.intermediary=Intermediary Bank SWIFT Code
+payment.swift.name.bank=Receiving Bank name
+payment.swift.name.intermediary=Intermediary Bank name
+payment.swift.branch.bank=Receiving Bank branch
+payment.swift.branch.intermediary=Intermediary Bank branch
+payment.swift.address.bank=Receiving Bank address
+payment.swift.address.intermediary=Intermediary Bank address
+payment.swift.address.beneficiary=Beneficiary address
+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.amazon.site=Buy giftcard at
payment.ask=Ask in Trader Chat
payment.uphold.accountId=Username or email or phone no.
@@ -3411,6 +3435,28 @@ payment.account.amazonGiftCard.addCountryInfo={0}\n\
This will not affect your account age status.
payment.amazonGiftCard.upgrade.headLine=Update Amazon Gift Card account
+payment.swift.info=Carefully review the core guidelines for using SWIFT on Bisq:\n\
+\n\
+- fill all fields completely and accurately \n\
+- buyer must send payment in currency specified by the offer maker \n\
+- buyer must use the shared fee model (SHA) \n\
+- buyer and seller may incur fees, so they should check their bank's fee schedules beforehand \n\
+\n\
+SWIFT is more sophisticated than other payment methods, so please take a moment to review full guidance on the wiki [HYPERLINK:https://bisq.wiki/SWIFT].
+
+payment.swift.info.buyer=To buy bitcoin with SWIFT, you must:\n\
+\n\
+- send payment in the currency specified by the offer maker \n\
+- use the shared fee model (SHA) to send payment\n\
+\n\
+Please review further guidance on the wiki to avoid penalties and ensure smooth trades [HYPERLINK:https://bisq.wiki/SWIFT].
+
+payment.swift.info.seller=SWIFT senders are required to use the shared payment model (SHA) to send payments.\n\
+\n\
+If you receive a SWIFT payment that does not use SHA, open a mediation ticket.\n\
+\n\
+Please review further guidance on the wiki to avoid penalties and ensure smooth trades [HYPERLINK:https://bisq.wiki/SWIFT].
+
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\
@@ -3581,6 +3627,8 @@ AMAZON_GIFT_CARD=Amazon eGift Card
BLOCK_CHAINS_INSTANT=Altcoins Instant
# suppress inspection "UnusedProperty"
CAPITUAL=Capitual
+# suppress inspection "UnusedProperty"
+SWIFT=SWIFT International Wire Transfer
# Deprecated: Cannot be deleted as it would break old trade history entries
# suppress inspection "UnusedProperty"
@@ -3639,6 +3687,8 @@ AMAZON_GIFT_CARD_SHORT=Amazon eGift Card
BLOCK_CHAINS_INSTANT_SHORT=Altcoins Instant
# suppress inspection "UnusedProperty"
CAPITUAL_SHORT=Capitual
+# suppress inspection "UnusedProperty"
+SWIFT_SHORT=SWIFT
# Deprecated: Cannot be deleted as it would break old trade history entries
# suppress inspection "UnusedProperty"
diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/SwiftForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/SwiftForm.java
new file mode 100644
index 00000000000..45d6d838f0a
--- /dev/null
+++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/SwiftForm.java
@@ -0,0 +1,351 @@
+/* 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.AutoTooltipButton;
+import bisq.desktop.components.AutoTooltipCheckBox;
+import bisq.desktop.components.InputTextField;
+import bisq.desktop.main.overlays.popups.Popup;
+import bisq.desktop.main.overlays.windows.SwiftPaymentDetails;
+import bisq.desktop.util.GUIUtil;
+import bisq.desktop.util.Layout;
+import bisq.desktop.util.validation.LengthValidator;
+
+import bisq.core.account.witness.AccountAgeWitnessService;
+import bisq.core.locale.Country;
+import bisq.core.locale.CountryUtil;
+import bisq.core.locale.Res;
+import bisq.core.payment.PaymentAccount;
+import bisq.core.payment.SwiftAccount;
+import bisq.core.payment.payload.PaymentAccountPayload;
+import bisq.core.payment.payload.SwiftAccountPayload;
+import bisq.core.trade.Trade;
+import bisq.core.util.coin.CoinFormatter;
+import bisq.core.util.validation.InputValidator;
+
+import com.jfoenix.controls.JFXTextArea;
+
+import javafx.scene.Node;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.control.TextArea;
+import javafx.scene.control.TitledPane;
+import javafx.scene.layout.GridPane;
+
+import javafx.geometry.Insets;
+
+import java.util.function.Consumer;
+
+import static bisq.common.util.Utilities.cleanString;
+import static bisq.core.payment.payload.SwiftAccountPayload.*;
+import static bisq.desktop.util.FormBuilder.addCompactTopLabelTextField;
+import static bisq.desktop.util.FormBuilder.addInputTextField;
+import static bisq.desktop.util.FormBuilder.addTopLabelTextArea;
+import static bisq.desktop.util.FormBuilder.addTopLabelTextField;
+
+public class SwiftForm extends PaymentMethodForm {
+ private final SwiftAccountPayload formData;
+ private final AutoTooltipCheckBox useIntermediaryCheck;
+ private final LengthValidator defaultValidator = new LengthValidator(2, 34);
+ private final LengthValidator swiftValidator = new LengthValidator(11, 11);
+ private final LengthValidator accountNrValidator = new LengthValidator(2, 40);
+ private final LengthValidator addressValidator = new LengthValidator(1, 100);
+
+ public SwiftForm(PaymentAccount paymentAccount,
+ AccountAgeWitnessService accountAgeWitnessService,
+ InputValidator defaultValidator, GridPane gridPane, int gridRow, CoinFormatter formatter) {
+ super(paymentAccount, accountAgeWitnessService, defaultValidator, gridPane, gridRow, formatter);
+ this.formData = ((SwiftAccount) paymentAccount).getPayload();
+ this.useIntermediaryCheck = new AutoTooltipCheckBox(Res.get("payment.swift.use.intermediary"));
+ }
+
+ @Override
+ public void addFormForAddAccount() {
+ ((SwiftAccount) paymentAccount).selectAllTradeCurrencies();
+ new Popup().information(Res.get("payment.swift.info"))
+ .width(900)
+ .closeButtonText(Res.get("shared.iUnderstand"))
+ .show();
+ gridRowFrom = gridRow + 1;
+ addFieldsForBankEdit(true, this::setBankSwiftCode, this::setBankName, this::setBankBranch, this::setBankAddress);
+ addFieldsForBankEdit(false, this::setIntermediarySwiftCode, this::setIntermediaryName, this::setIntermediaryBranch, this::setIntermediaryAddress);
+ addFieldsForBeneficiaryEdit();
+ addLimitations(false);
+ addAccountNameTextFieldWithAutoFillToggleButton();
+ }
+
+ @Override
+ protected void autoFillNameTextField() {
+ setAccountNameWithString(formData.getBeneficiaryName());
+ }
+
+ @Override
+ public void addFormForDisplayAccount() {
+ gridRowFrom = gridRow;
+ addTopLabelTextField(gridPane, gridRow, Res.get("payment.account.name"), paymentAccount.getAccountName(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
+ addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.paymentMethod"), Res.get(paymentAccount.getPaymentMethod().getId()));
+
+ addCompactTopLabelTextField(gridPane, ++gridRow, Res.get(SWIFT_CODE + BANKPOSTFIX), formData.getBankSwiftCode());
+ addCompactTopLabelTextField(gridPane, ++gridRow, Res.get(COUNTRY + BANKPOSTFIX), CountryUtil.getNameAndCode(formData.getBankCountryCode()));
+ addCompactTopLabelTextField(gridPane, ++gridRow, Res.get(SNAME + BANKPOSTFIX), formData.getBankName());
+ addCompactTopLabelTextField(gridPane, ++gridRow, Res.get(BRANCH + BANKPOSTFIX), formData.getBankBranch());
+ addCompactTopLabelTextField(gridPane, ++gridRow, Res.get(ADDRESS + BANKPOSTFIX), cleanString(formData.getBankAddress()));
+
+ if (formData.usesIntermediaryBank()) {
+ addCompactTopLabelTextField(gridPane, ++gridRow, Res.get(SWIFT_CODE + INTERMEDIARYPOSTFIX), formData.getIntermediarySwiftCode(), Layout.GROUP_DISTANCE_WITHOUT_SEPARATOR);
+ addCompactTopLabelTextField(gridPane, ++gridRow, Res.get(COUNTRY + INTERMEDIARYPOSTFIX), CountryUtil.getNameAndCode(formData.getIntermediaryCountryCode()));
+ addCompactTopLabelTextField(gridPane, ++gridRow, Res.get(SNAME + INTERMEDIARYPOSTFIX), formData.getIntermediaryName());
+ addCompactTopLabelTextField(gridPane, ++gridRow, Res.get(BRANCH + INTERMEDIARYPOSTFIX), formData.getIntermediaryBranch());
+ addCompactTopLabelTextField(gridPane, ++gridRow, Res.get(ADDRESS + INTERMEDIARYPOSTFIX), cleanString(formData.getIntermediaryAddress()));
+ }
+
+ addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.account.owner"), formData.getBeneficiaryName(), Layout.GROUP_DISTANCE_WITHOUT_SEPARATOR);
+ addCompactTopLabelTextField(gridPane, ++gridRow, Res.get(SWIFT_ACCOUNT), formData.getBeneficiaryAccountNr());
+ addCompactTopLabelTextField(gridPane, ++gridRow, Res.get(ADDRESS + BENEFICIARYPOSTFIX), cleanString(formData.getBeneficiaryAddress()));
+ addCompactTopLabelTextField(gridPane, ++gridRow, Res.get(PHONE + BENEFICIARYPOSTFIX), formData.getBeneficiaryPhone());
+ addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.account.city"), formData.getBeneficiaryCity());
+ addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.country"), CountryUtil.getNameAndCode(formData.getBankCountryCode())); // same as receiving bank country
+ addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.shared.extraInfo"), cleanString(formData.getSpecialInstructions()));
+
+ gridPane.add(new Label(""), 0, ++gridRow); // spacer
+ addLimitations(true);
+ }
+
+ @Override
+ public void updateAllInputsValid() {
+ SwiftAccountPayload data = formData;
+
+ // intermediary bank details are optional, but if specified must be valid
+ boolean intermediaryValidIfSpecified = !useIntermediaryCheck.isSelected() && !data.usesIntermediaryBank() ||
+ data.usesIntermediaryBank() && (swiftValidator.validate(data.getIntermediarySwiftCode()).isValid
+ && defaultValidator.validate(data.getIntermediaryCountryCode()).isValid
+ && defaultValidator.validate(data.getIntermediaryName()).isValid
+ && defaultValidator.validate(data.getIntermediaryBranch()).isValid
+ && addressValidator.validate(data.getIntermediaryAddress()).isValid
+ );
+
+ allInputsValid.set(isAccountNameValid()
+ && swiftValidator.validate(data.getBankSwiftCode()).isValid
+ && defaultValidator.validate(data.getBankCountryCode()).isValid
+ && defaultValidator.validate(data.getBankName()).isValid
+ && defaultValidator.validate(data.getBankBranch()).isValid
+ && addressValidator.validate(data.getBankAddress()).isValid
+ && defaultValidator.validate(data.getBeneficiaryName()).isValid
+ && accountNrValidator.validate(data.getBeneficiaryAccountNr()).isValid
+ && addressValidator.validate(data.getBeneficiaryAddress()).isValid
+ && defaultValidator.validate(data.getBeneficiaryPhone()).isValid
+ && defaultValidator.validate(data.getBeneficiaryCity()).isValid
+ && paymentAccount.getTradeCurrencies().size() > 0
+ && intermediaryValidIfSpecified);
+ }
+
+ // Here we need to show information to buyer so they can make the fiat payment, however there is only enough space
+ // on the trade screen for ~4 fields.
+ // Since SWIFT has an unusually large number of fields, it will be better to offer a button which will show
+ // the SWIFT information in a popup screen.
+ public static int addFormForBuyer(GridPane gridPane, int gridRow,
+ PaymentAccountPayload paymentAccountPayload, Trade trade) {
+ SwiftAccountPayload swiftAccountPayload = (SwiftAccountPayload) paymentAccountPayload;
+ Button button = new AutoTooltipButton(Res.get("payment.swift.showPaymentInfo"));
+ GridPane.setRowIndex(button, gridRow);
+ GridPane.setColumnIndex(button, 1);
+ gridPane.getChildren().add(button);
+ GridPane.setMargin(button, new Insets(Layout.TWICE_FIRST_ROW_AND_GROUP_DISTANCE, 0, 0, Layout.FLOATING_LABEL_DISTANCE));
+ button.setOnAction((e) -> new SwiftPaymentDetails(swiftAccountPayload, trade).show());
+ return gridRow;
+ }
+
+ private void addFieldsForBankEdit(boolean isPrimary,
+ Consumer onSwiftCodeSelected,
+ Consumer onNameSelected,
+ Consumer onBranchSelected,
+ Consumer onAddressSelected) {
+ GridPane gridPane2 = new GridPane();
+ gridPane2.getColumnConstraints().add(gridPane.getColumnConstraints().get(0));
+ TitledPane titledPane = new TitledPane(isPrimary ? Res.get("payment.swift.title" + BANKPOSTFIX) : Res.get("payment.swift.title" + INTERMEDIARYPOSTFIX), gridPane2);
+ titledPane.setExpanded(isPrimary);
+ gridPane.add(titledPane, 0, ++gridRow);
+
+ int gridRow2 = 0;
+ if (!isPrimary) {
+ // secondary bank (optional) has a checkbox to specify if it is being used
+ gridPane2.add(useIntermediaryCheck, 0, ++gridRow2);
+ }
+ String label = isPrimary ? Res.get(SWIFT_CODE + BANKPOSTFIX) : Res.get(SWIFT_CODE + INTERMEDIARYPOSTFIX);
+ InputTextField bankSwiftCodeField = addInputTextField(gridPane2, ++gridRow2, label);
+ bankSwiftCodeField.setPromptText(label);
+ bankSwiftCodeField.setValidator(swiftValidator);
+ bankSwiftCodeField.textProperty().addListener((ov, oldValue, newValue) -> onSwiftCodeSelected.accept(newValue));
+
+ if (isPrimary) {
+ gridRow2 = GUIUtil.addRegionCountry(gridPane2, gridRow2, this::setBankCountry);
+ } else {
+ gridRow2 = GUIUtil.addRegionCountry(gridPane2, ++gridRow2, this::setIntermediaryCountry);
+ }
+
+ label = isPrimary ? Res.get(SNAME + BANKPOSTFIX) : Res.get(SNAME + INTERMEDIARYPOSTFIX);
+ InputTextField bankNameField = addInputTextField(gridPane2, ++gridRow2, label);
+ bankNameField.setPromptText(label);
+ bankNameField.setValidator(defaultValidator);
+ bankNameField.textProperty().addListener((ov, oldValue, newValue) -> onNameSelected.accept(newValue));
+
+ label = isPrimary ? Res.get(BRANCH + BANKPOSTFIX) : Res.get(BRANCH + INTERMEDIARYPOSTFIX);
+ InputTextField bankBranchField = addInputTextField(gridPane2, ++gridRow2, label);
+ bankBranchField.setPromptText(label);
+ bankBranchField.setValidator(defaultValidator);
+ bankBranchField.textProperty().addListener((ov, oldValue, newValue) -> onBranchSelected.accept(newValue));
+
+ label = isPrimary ? Res.get(ADDRESS + BANKPOSTFIX) : Res.get(ADDRESS + INTERMEDIARYPOSTFIX);
+ TextArea bankAddressTextArea = addTopLabelTextArea(gridPane2, ++gridRow2, label, label).second;
+ bankAddressTextArea.setMinHeight(70);
+ bankAddressTextArea.textProperty().addListener((ov, oldValue, newValue) -> onAddressSelected.accept(newValue));
+
+ // intermediary bank can be enabled/disabled via checkbox
+ if (!isPrimary) {
+ useIntermediaryCheck.setOnAction((e) -> {
+ for (Node x : gridPane2.getChildren()) {
+ if (x == useIntermediaryCheck)
+ continue;
+ x.setDisable(!useIntermediaryCheck.isSelected());
+ }
+ if (!useIntermediaryCheck.isSelected()) {
+ bankSwiftCodeField.setText("");
+ bankNameField.setText("");
+ bankBranchField.setText("");
+ bankAddressTextArea.setText("");
+ }
+ updateFromInputs();
+ });
+ // make the intermediary fields initially greyed out
+ for (Node x : gridPane2.getChildren()) {
+ if (x == useIntermediaryCheck)
+ continue;
+ x.setDisable(!useIntermediaryCheck.isSelected());
+ }
+ }
+ }
+
+ private void addFieldsForBeneficiaryEdit() {
+ String label = Res.get("payment.account.owner");
+ InputTextField beneficiaryNameField = addInputTextField(gridPane, ++gridRow, label);
+ beneficiaryNameField.setPromptText(label);
+ beneficiaryNameField.setValidator(defaultValidator);
+ beneficiaryNameField.textProperty().addListener((ov, oldValue, newValue) -> {
+ formData.setBeneficiaryName(newValue.trim());
+ updateFromInputs();
+ });
+
+ label = Res.get(SWIFT_ACCOUNT);
+ InputTextField beneficiaryAccountNrField = addInputTextField(gridPane, ++gridRow, label);
+ beneficiaryAccountNrField.setPromptText(label);
+ beneficiaryAccountNrField.setValidator(defaultValidator);
+ beneficiaryAccountNrField.setValidator(accountNrValidator);
+ beneficiaryAccountNrField.textProperty().addListener((ov, oldValue, newValue) -> {
+ formData.setBeneficiaryAccountNr(newValue.trim());
+ updateFromInputs();
+ });
+
+ label = Res.get(ADDRESS + BENEFICIARYPOSTFIX);
+ TextArea beneficiaryAddressTextArea = addTopLabelTextArea(gridPane, ++gridRow, label, label).second;
+ beneficiaryAddressTextArea.setMinHeight(70);
+ beneficiaryAddressTextArea.textProperty().addListener((ov, oldValue, newValue) -> {
+ formData.setBeneficiaryAddress(newValue.trim());
+ updateFromInputs();
+ });
+
+ label = Res.get("payment.account.city");
+ InputTextField beneficiaryCityField = addInputTextField(gridPane, ++gridRow, label);
+ beneficiaryCityField.setPromptText(label);
+ beneficiaryCityField.setValidator(defaultValidator);
+ beneficiaryCityField.textProperty().addListener((ov, oldValue, newValue) -> {
+ formData.setBeneficiaryCity(newValue.trim());
+ updateFromInputs();
+ });
+
+ label = Res.get(PHONE + BENEFICIARYPOSTFIX);
+ InputTextField beneficiaryPhoneField = addInputTextField(gridPane, ++gridRow, label);
+ beneficiaryPhoneField.setPromptText(label);
+ beneficiaryPhoneField.setValidator(defaultValidator);
+ beneficiaryPhoneField.textProperty().addListener((ov, oldValue, newValue) -> {
+ formData.setBeneficiaryPhone(newValue.trim());
+ updateFromInputs();
+ });
+
+ label = Res.get("payment.shared.optionalExtra");
+ TextArea extraTextArea = addTopLabelTextArea(gridPane, ++gridRow, label, label).second;
+ extraTextArea.setMinHeight(70);
+ ((JFXTextArea) extraTextArea).setLabelFloat(false);
+ extraTextArea.textProperty().addListener((ov, oldValue, newValue) -> {
+ formData.setSpecialInstructions(newValue.trim());
+ updateFromInputs();
+ });
+ }
+
+ private void setBankSwiftCode(String value) {
+ formData.setBankSwiftCode(value.trim());
+ updateFromInputs();
+ }
+
+ private void setBankName(String value) {
+ formData.setBankName(value.trim());
+ updateFromInputs();
+ }
+
+ private void setBankBranch(String value) {
+ formData.setBankBranch(value.trim());
+ updateFromInputs();
+ }
+
+ private void setBankAddress(String value) {
+ formData.setBankAddress(value.trim());
+ updateFromInputs();
+ }
+
+ private void setIntermediarySwiftCode(String value) {
+ formData.setIntermediarySwiftCode(value.trim());
+ updateFromInputs();
+ }
+
+ private void setIntermediaryName(String value) {
+ formData.setIntermediaryName(value.trim());
+ updateFromInputs();
+ }
+
+ private void setIntermediaryBranch(String value) {
+ formData.setIntermediaryBranch(value.trim());
+ updateFromInputs();
+ }
+
+ private void setIntermediaryAddress(String value) {
+ formData.setIntermediaryAddress(value.trim());
+ updateFromInputs();
+ }
+
+ private void setBankCountry(Country country) {
+ if (country == null)
+ return;
+ formData.setBankCountryCode(country.code);
+ updateFromInputs();
+ }
+
+ private void setIntermediaryCountry(Country country) {
+ if (country == null)
+ return;
+ formData.setIntermediaryCountryCode(country.code);
+ updateFromInputs();
+ }
+}
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 d94b4b18728..09e3cb37b22 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
@@ -45,6 +45,7 @@
import bisq.desktop.components.paymentmethods.SepaForm;
import bisq.desktop.components.paymentmethods.SepaInstantForm;
import bisq.desktop.components.paymentmethods.SpecificBankForm;
+import bisq.desktop.components.paymentmethods.SwiftForm;
import bisq.desktop.components.paymentmethods.SwishForm;
import bisq.desktop.components.paymentmethods.TransferwiseForm;
import bisq.desktop.components.paymentmethods.PayseraForm;
@@ -543,6 +544,8 @@ private PaymentMethodForm getPaymentMethodForm(PaymentMethod paymentMethod, Paym
return new AmazonGiftCardForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter);
case PaymentMethod.CAPITUAL_ID:
return new CapitualForm(paymentAccount, accountAgeWitnessService, capitualValidator, inputValidator, root, gridRow, formatter);
+ case PaymentMethod.SWIFT_ID:
+ return new SwiftForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter);
default:
log.error("Not supported PaymentMethod: " + paymentMethod);
return null;
diff --git a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferView.java b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferView.java
index 3794dc1b63f..5ac9a51b264 100644
--- a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferView.java
+++ b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferView.java
@@ -168,7 +168,7 @@ public abstract class MutableOfferView> exten
protected int gridRow = 0;
private final List editOfferElements = new ArrayList<>();
- private boolean clearXchangeWarningDisplayed, fasterPaymentsWarningDisplayed, isActivated;
+ private boolean clearXchangeWarningDisplayed, fasterPaymentsWarningDisplayed, swiftWarningDisplayed, isActivated;
private InfoInputTextField marketBasedPriceInfoInputTextField, volumeInfoInputTextField,
buyerSecurityDepositInfoInputTextField, triggerPriceInfoInputTextField;
private AutoTooltipSlideToggleButton tradeFeeInBtcToggle, tradeFeeInBsqToggle;
@@ -499,6 +499,19 @@ private void maybeShowFasterPaymentsWarning(PaymentAccount paymentAccount) {
}
}
+ private void maybeShowSwiftWarning(PaymentAccount paymentAccount) {
+ if (paymentAccount.getPaymentMethod().getId().equals(PaymentMethod.SWIFT_ID) && !swiftWarningDisplayed) {
+ swiftWarningDisplayed = true;
+ UserThread.runAfter(() -> {
+ if (model.getDataModel().isBuyOffer()) {
+ GUIUtil.showSwiftWarningToBuyer();
+ } else {
+ GUIUtil.showSwiftWarningToSeller();
+ }
+ }, 500, TimeUnit.MILLISECONDS);
+ }
+ }
+
protected void onPaymentAccountsComboBoxSelected() {
// Temporary deactivate handler as the payment account change can populate a new currency list and causes
// unwanted selection events (item 0)
@@ -508,6 +521,7 @@ protected void onPaymentAccountsComboBoxSelected() {
if (paymentAccount != null) {
maybeShowClearXchangeWarning(paymentAccount);
maybeShowFasterPaymentsWarning(paymentAccount);
+ maybeShowSwiftWarning(paymentAccount);
currencySelection.setVisible(paymentAccount.hasMultipleCurrencies());
currencySelection.setManaged(paymentAccount.hasMultipleCurrencies());
diff --git a/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferView.java b/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferView.java
index 1d43cdd65ed..c8af97a49ea 100644
--- a/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferView.java
+++ b/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferView.java
@@ -163,7 +163,7 @@ public class TakeOfferView extends ActivatableViewAndModel amountFocusedListener, getShowWalletFundedNotificationListener;
@@ -309,6 +309,7 @@ protected void activate() {
maybeShowTakeOfferFromUnsignedAccountWarning(model.dataModel.getOffer());
maybeShowClearXchangeWarning(lastPaymentAccount);
maybeShowFasterPaymentsWarning(lastPaymentAccount);
+ maybeShowSwiftWarning(lastPaymentAccount);
maybeShowCashByMailWarning(lastPaymentAccount, model.dataModel.getOffer());
if (!DevEnv.isDaoActivated() && !model.isRange()) {
@@ -831,6 +832,7 @@ private void addPaymentGroup() {
if (paymentAccount != null) {
maybeShowClearXchangeWarning(paymentAccount);
maybeShowFasterPaymentsWarning(paymentAccount);
+ maybeShowSwiftWarning(paymentAccount);
}
model.onPaymentAccountSelected(paymentAccount);
});
@@ -1272,6 +1274,19 @@ private void maybeShowFasterPaymentsWarning(PaymentAccount paymentAccount) {
}
}
+ private void maybeShowSwiftWarning(PaymentAccount paymentAccount) {
+ if (paymentAccount.getPaymentMethod().getId().equals(PaymentMethod.SWIFT_ID) && !swiftWarningDisplayed) {
+ swiftWarningDisplayed = true;
+ UserThread.runAfter(() -> {
+ if (model.getOffer().getDirection() == OfferPayload.Direction.BUY) {
+ GUIUtil.showSwiftWarningToSeller(); // taking an offer to buy, we are the seller
+ } else {
+ GUIUtil.showSwiftWarningToBuyer(); // taking an offer to sell, we are the buyer
+ }
+ }, 500, TimeUnit.MILLISECONDS);
+ }
+ }
+
private void maybeShowCashByMailWarning(PaymentAccount paymentAccount, Offer offer) {
if (paymentAccount.getPaymentMethod().getId().equals(PaymentMethod.CASH_BY_MAIL_ID) &&
!cashByMailWarningDisplayed && !offer.getExtraInfo().isEmpty()) {
diff --git a/desktop/src/main/java/bisq/desktop/main/overlays/windows/SwiftPaymentDetails.java b/desktop/src/main/java/bisq/desktop/main/overlays/windows/SwiftPaymentDetails.java
new file mode 100644
index 00000000000..18556ad9534
--- /dev/null
+++ b/desktop/src/main/java/bisq/desktop/main/overlays/windows/SwiftPaymentDetails.java
@@ -0,0 +1,114 @@
+/*
+ * 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.main.overlays.windows;
+
+import bisq.desktop.main.overlays.Overlay;
+import bisq.desktop.util.DisplayUtils;
+
+import bisq.core.locale.CountryUtil;
+import bisq.core.locale.Res;
+import bisq.core.payment.payload.SwiftAccountPayload;
+import bisq.core.trade.Trade;
+
+import javafx.scene.control.Label;
+import javafx.geometry.Insets;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static bisq.common.util.Utilities.cleanString;
+import static bisq.common.util.Utilities.copyToClipboard;
+import static bisq.core.payment.payload.SwiftAccountPayload.*;
+import static bisq.desktop.util.FormBuilder.addConfirmationLabelLabel;
+import static bisq.desktop.util.FormBuilder.addTitledGroupBg;
+
+public class SwiftPaymentDetails extends Overlay {
+ private final SwiftAccountPayload payload;
+ private final Trade trade;
+ private final List copyToClipboardData = new ArrayList<>();
+
+ public SwiftPaymentDetails(SwiftAccountPayload swiftAccountPayload, Trade trade) {
+ this.payload = swiftAccountPayload;
+ this.trade = trade;
+ }
+
+ public void show() {
+ rowIndex = -1;
+ width = 918;
+ createGridPane();
+ addContent();
+ addButtons();
+ display();
+ }
+
+ @Override
+ protected void cleanup() {
+ }
+
+ @Override
+ protected void createGridPane() {
+ super.createGridPane();
+ gridPane.setPadding(new Insets(35, 40, 30, 40));
+ gridPane.getStyleClass().add("grid-pane");
+ }
+
+ private void addContent() {
+ int rows = payload.usesIntermediaryBank() ? 22 : 16;
+ addTitledGroupBg(gridPane, ++rowIndex, rows, Res.get("payment.swift.headline"));
+
+ gridPane.add(new Label(""), 0, ++rowIndex); // spacer
+ addLabelsAndCopy(Res.get("portfolio.pending.step2_buyer.amountToTransfer"), DisplayUtils.formatVolumeWithCode(trade.getTradeVolume()));
+ addLabelsAndCopy(Res.get(SWIFT_CODE + BANKPOSTFIX), payload.getBankSwiftCode());
+ addLabelsAndCopy(Res.get(SNAME + BANKPOSTFIX), payload.getBankName());
+ addLabelsAndCopy(Res.get(BRANCH + BANKPOSTFIX), payload.getBankBranch());
+ addLabelsAndCopy(Res.get(ADDRESS + BANKPOSTFIX), cleanString(payload.getBankAddress()));
+ addLabelsAndCopy(Res.get(COUNTRY + BANKPOSTFIX), CountryUtil.getNameAndCode(payload.getBankCountryCode()));
+
+ if (payload.usesIntermediaryBank()) {
+ gridPane.add(new Label(""), 0, ++rowIndex); // spacer
+ addLabelsAndCopy(Res.get(SWIFT_CODE + INTERMEDIARYPOSTFIX), payload.getIntermediarySwiftCode());
+ addLabelsAndCopy(Res.get(SNAME + INTERMEDIARYPOSTFIX), payload.getIntermediaryName());
+ addLabelsAndCopy(Res.get(BRANCH + INTERMEDIARYPOSTFIX), payload.getIntermediaryBranch());
+ addLabelsAndCopy(Res.get(ADDRESS + INTERMEDIARYPOSTFIX), cleanString(payload.getIntermediaryAddress()));
+ addLabelsAndCopy(Res.get(COUNTRY + INTERMEDIARYPOSTFIX), CountryUtil.getNameAndCode(payload.getIntermediaryCountryCode()));
+ }
+
+ gridPane.add(new Label(""), 0, ++rowIndex); // spacer
+ addLabelsAndCopy(Res.get("payment.account.owner"), payload.getBeneficiaryName());
+ addLabelsAndCopy(Res.get(SWIFT_ACCOUNT), payload.getBeneficiaryAccountNr());
+ addLabelsAndCopy(Res.get(ADDRESS + BENEFICIARYPOSTFIX), cleanString(payload.getBeneficiaryAddress()));
+ addLabelsAndCopy(Res.get(PHONE + BENEFICIARYPOSTFIX), payload.getBeneficiaryPhone());
+ addLabelsAndCopy(Res.get("payment.account.city"), payload.getBeneficiaryCity());
+ addLabelsAndCopy(Res.get("payment.country"), CountryUtil.getNameAndCode(payload.getBankCountryCode()));
+ addLabelsAndCopy(Res.get("payment.shared.extraInfo"), cleanString(payload.getSpecialInstructions()));
+
+ actionButtonText(Res.get("shared.copyToClipboard"));
+ onAction(() -> {
+ StringBuilder work = new StringBuilder();
+ for (String s : copyToClipboardData) {
+ work.append(s).append(System.lineSeparator());
+ }
+ copyToClipboard(work.toString());
+ });
+ }
+
+ private void addLabelsAndCopy(String title, String value) {
+ addConfirmationLabelLabel(gridPane, ++rowIndex, title, value);
+ copyToClipboardData.add(title + " : " + value);
+ }
+}
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 167b9140f6f..278de94f84a 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
@@ -48,6 +48,7 @@
import bisq.desktop.components.paymentmethods.SepaForm;
import bisq.desktop.components.paymentmethods.SepaInstantForm;
import bisq.desktop.components.paymentmethods.SpecificBankForm;
+import bisq.desktop.components.paymentmethods.SwiftForm;
import bisq.desktop.components.paymentmethods.SwishForm;
import bisq.desktop.components.paymentmethods.TransferwiseForm;
import bisq.desktop.components.paymentmethods.USPostalMoneyOrderForm;
@@ -81,6 +82,7 @@
import bisq.core.payment.payload.MoneyGramAccountPayload;
import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.payment.payload.PaymentMethod;
+import bisq.core.payment.payload.SwiftAccountPayload;
import bisq.core.payment.payload.USPostalMoneyOrderAccountPayload;
import bisq.core.payment.payload.WesternUnionAccountPayload;
import bisq.core.trade.Trade;
@@ -335,6 +337,9 @@ protected void addContent() {
case PaymentMethod.CAPITUAL_ID:
gridRow = CapitualForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload);
break;
+ case PaymentMethod.SWIFT_ID:
+ gridRow = SwiftForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload, trade);
+ break;
default:
log.error("Not supported PaymentMethod: " + paymentMethodId);
}
@@ -604,6 +609,10 @@ private void showPopup() {
} else if (paymentAccountPayload instanceof CashByMailAccountPayload ||
paymentAccountPayload instanceof HalCashAccountPayload) {
message += Res.get("portfolio.pending.step2_buyer.pay", amount);
+ } else if (paymentAccountPayload instanceof SwiftAccountPayload) {
+ message += Res.get("portfolio.pending.step2_buyer.pay", amount) +
+ refTextWarn + "\n\n" +
+ Res.get("portfolio.pending.step2_buyer.fees.swift");
} else {
message += Res.get("portfolio.pending.step2_buyer.pay", amount) +
refTextWarn + "\n\n" +
diff --git a/desktop/src/main/java/bisq/desktop/util/GUIUtil.java b/desktop/src/main/java/bisq/desktop/util/GUIUtil.java
index 6160a860cae..f5177b3a154 100644
--- a/desktop/src/main/java/bisq/desktop/util/GUIUtil.java
+++ b/desktop/src/main/java/bisq/desktop/util/GUIUtil.java
@@ -778,6 +778,24 @@ public static void showFasterPaymentsWarning(Navigation navigation) {
.show();
}
+ public static void showSwiftWarningToBuyer() {
+ String key = "confirmSwiftRequirementsBuyer";
+ new Popup().information(Res.get("payment.swift.info.buyer"))
+ .width(900)
+ .closeButtonText(Res.get("shared.iConfirm"))
+ .dontShowAgainId(key)
+ .show();
+ }
+
+ public static void showSwiftWarningToSeller() {
+ String key = "confirmSwiftRequirementsSeller";
+ new Popup().information(Res.get("payment.swift.info.seller"))
+ .width(900)
+ .closeButtonText(Res.get("shared.iConfirm"))
+ .dontShowAgainId(key)
+ .show();
+ }
+
public static String getBitcoinURI(String address, Coin amount, String label) {
return address != null ?
BitcoinURI.convertToBitcoinURI(Address.fromString(Config.baseCurrencyNetworkParameters(),
diff --git a/proto/src/main/proto/pb.proto b/proto/src/main/proto/pb.proto
index 0b19e1c7e31..b268b65c8c5 100644
--- a/proto/src/main/proto/pb.proto
+++ b/proto/src/main/proto/pb.proto
@@ -999,6 +999,7 @@ message PaymentAccountPayload {
CapitualAccountPayload capitual_account_payload = 33;
PayseraAccountPayload Paysera_account_payload = 34;
PaxumAccountPayload Paxum_account_payload = 35;
+ SwiftAccountPayload swift_account_payload = 36;
}
map exclude_from_json_data = 15;
}
@@ -1232,6 +1233,27 @@ message CapitualAccountPayload {
string account_nr = 1;
}
+message SwiftAccountPayload {
+ string beneficiary_name = 1;
+ string beneficiary_account_nr = 2;
+ string beneficiary_address = 3;
+ string beneficiary_city = 4;
+ string beneficiary_phone = 5;
+ string special_instructions = 6;
+
+ string bank_swift_code = 7;
+ string bank_country_code = 8;
+ string bank_name = 9;
+ string bank_branch = 10;
+ string bank_address = 11;
+
+ string intermediary_swift_code = 12;
+ string intermediary_country_code = 13;
+ string intermediary_name = 14;
+ string intermediary_branch = 15;
+ string intermediary_address = 16;
+}
+
///////////////////////////////////////////////////////////////////////////////////////////
// PersistableEnvelope
///////////////////////////////////////////////////////////////////////////////////////////