Merge pull request #4726 from chimp1984/add-transferwise-payment-method

Add transferwise account
This commit is contained in:
sqrrm 2020-10-31 13:20:41 +01:00 committed by GitHub
commit 605f4b3015
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 390 additions and 3 deletions

View file

@ -267,6 +267,58 @@ public class CurrencyUtil {
return currencies;
}
// https://github.com/bisq-network/proposals/issues/243
public static List<TradeCurrency> getAllTransferwiseCurrencies() {
ArrayList<TradeCurrency> currencies = new ArrayList<>(Arrays.asList(
new FiatCurrency("ARS"),
new FiatCurrency("AUD"),
new FiatCurrency("XOF"),
new FiatCurrency("BGN"),
new FiatCurrency("CAD"),
new FiatCurrency("CLP"),
new FiatCurrency("HRK"),
new FiatCurrency("CZK"),
new FiatCurrency("DKK"),
new FiatCurrency("EGP"),
new FiatCurrency("EUR"),
new FiatCurrency("GEL"),
new FiatCurrency("HKD"),
new FiatCurrency("HUF"),
new FiatCurrency("IDR"),
new FiatCurrency("ILS"),
new FiatCurrency("JPY"),
new FiatCurrency("KES"),
new FiatCurrency("MYR"),
new FiatCurrency("MXN"),
new FiatCurrency("MAD"),
new FiatCurrency("NPR"),
new FiatCurrency("NZD"),
new FiatCurrency("NGN"),
new FiatCurrency("NOK"),
new FiatCurrency("PKR"),
new FiatCurrency("PEN"),
new FiatCurrency("PHP"),
new FiatCurrency("PLN"),
new FiatCurrency("RON"),
new FiatCurrency("RUB"),
new FiatCurrency("SGD"),
new FiatCurrency("ZAR"),
new FiatCurrency("KRW"),
new FiatCurrency("SEK"),
new FiatCurrency("CHF"),
new FiatCurrency("THB"),
new FiatCurrency("TRY"),
new FiatCurrency("UGX"),
new FiatCurrency("AED"),
new FiatCurrency("GBP"),
new FiatCurrency("VND"),
new FiatCurrency("ZMW")
));
currencies.sort(Comparator.comparing(TradeCurrency::getCode));
return currencies;
}
// https://www.revolut.com/help/getting-started/exchanging-currencies/what-fiat-currencies-are-supported-for-holding-and-exchange
public static List<TradeCurrency> getAllRevolutCurrencies() {
ArrayList<TradeCurrency> currencies = new ArrayList<>(Arrays.asList(

View file

@ -76,6 +76,8 @@ public class PaymentAccountFactory {
return new PromptPayAccount();
case PaymentMethod.ADVANCED_CASH_ID:
return new AdvancedCashAccount();
case PaymentMethod.TRANSFERWISE_ID:
return new TransferwiseAccount();
case PaymentMethod.BLOCK_CHAINS_INSTANT_ID:
return new InstantCryptoCurrencyAccount();

View file

@ -0,0 +1,47 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.core.payment;
import bisq.core.locale.CurrencyUtil;
import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.payment.payload.PaymentMethod;
import bisq.core.payment.payload.TransferwiseAccountPayload;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
public final class TransferwiseAccount extends PaymentAccount {
public TransferwiseAccount() {
super(PaymentMethod.TRANSFERWISE);
tradeCurrencies.addAll(CurrencyUtil.getAllTransferwiseCurrencies());
}
@Override
protected PaymentAccountPayload createPayload() {
return new TransferwiseAccountPayload(paymentMethod.getId(), id);
}
public void setEmail(String accountId) {
((TransferwiseAccountPayload) paymentAccountPayload).setEmail(accountId);
}
public String getEmail() {
return ((TransferwiseAccountPayload) paymentAccountPayload).getEmail();
}
}

View file

@ -91,6 +91,7 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme
public static final String BLOCK_CHAINS_ID = "BLOCK_CHAINS";
public static final String PROMPT_PAY_ID = "PROMPT_PAY";
public static final String ADVANCED_CASH_ID = "ADVANCED_CASH";
public static final String TRANSFERWISE_ID = "TRANSFERWISE";
public static final String BLOCK_CHAINS_INSTANT_ID = "BLOCK_CHAINS_INSTANT";
// Cannot be deleted as it would break old trade history entries
@ -128,6 +129,7 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme
public static PaymentMethod BLOCK_CHAINS;
public static PaymentMethod PROMPT_PAY;
public static PaymentMethod ADVANCED_CASH;
public static PaymentMethod TRANSFERWISE;
public static PaymentMethod BLOCK_CHAINS_INSTANT;
// Cannot be deleted as it would break old trade history entries
@ -178,6 +180,7 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme
REVOLUT = new PaymentMethod(REVOLUT_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK),
PERFECT_MONEY = new PaymentMethod(PERFECT_MONEY_ID, DAY, DEFAULT_TRADE_LIMIT_LOW_RISK),
ADVANCED_CASH = new PaymentMethod(ADVANCED_CASH_ID, DAY, DEFAULT_TRADE_LIMIT_VERY_LOW_RISK),
TRANSFERWISE = new PaymentMethod(TRANSFERWISE_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK),
// Japan
JAPAN_BANK = new PaymentMethod(JAPAN_BANK_ID, DAY, DEFAULT_TRADE_LIMIT_LOW_RISK),
@ -347,8 +350,9 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme
public static boolean hasChargebackRisk(String id, String currencyCode) {
if (CurrencyUtil.getMatureMarketCurrencies().stream()
.noneMatch(c -> c.getCode().equals(currencyCode)))
.noneMatch(c -> c.getCode().equals(currencyCode)))
return false;
return id.equals(PaymentMethod.SEPA_ID) ||
id.equals(PaymentMethod.SEPA_INSTANT_ID) ||
id.equals(PaymentMethod.INTERAC_E_TRANSFER_ID) ||

View file

@ -0,0 +1,99 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.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 TransferwiseAccountPayload extends PaymentAccountPayload {
private String email = "";
public TransferwiseAccountPayload(String paymentMethod, String id) {
super(paymentMethod, id);
}
///////////////////////////////////////////////////////////////////////////////////////////
// PROTO BUFFER
///////////////////////////////////////////////////////////////////////////////////////////
private TransferwiseAccountPayload(String paymentMethod,
String id,
String email,
long maxTradePeriod,
Map<String, String> excludeFromJsonDataMap) {
super(paymentMethod,
id,
maxTradePeriod,
excludeFromJsonDataMap);
this.email = email;
}
@Override
public Message toProtoMessage() {
return getPaymentAccountPayloadBuilder()
.setTransferwiseAccountPayload(protobuf.TransferwiseAccountPayload.newBuilder().setEmail(email))
.build();
}
public static TransferwiseAccountPayload fromProto(protobuf.PaymentAccountPayload proto) {
return new TransferwiseAccountPayload(proto.getPaymentMethodId(),
proto.getId(),
proto.getTransferwiseAccountPayload().getEmail(),
proto.getMaxTradePeriod(),
new HashMap<>(proto.getExcludeFromJsonDataMap()));
}
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public String getPaymentDetails() {
return Res.get(paymentMethodId) + " - " + Res.getWithCol("payment.email") + " " + email;
}
@Override
public String getPaymentDetailsForTradePopup() {
return getPaymentDetails();
}
@Override
public byte[] getAgeWitnessInputData() {
return super.getAgeWitnessInputData(email.getBytes(StandardCharsets.UTF_8));
}
}

View file

@ -48,6 +48,7 @@ import bisq.core.payment.payload.SepaAccountPayload;
import bisq.core.payment.payload.SepaInstantAccountPayload;
import bisq.core.payment.payload.SpecificBanksAccountPayload;
import bisq.core.payment.payload.SwishAccountPayload;
import bisq.core.payment.payload.TransferwiseAccountPayload;
import bisq.core.payment.payload.USPostalMoneyOrderAccountPayload;
import bisq.core.payment.payload.UpholdAccountPayload;
import bisq.core.payment.payload.VenmoAccountPayload;
@ -145,6 +146,8 @@ public class CoreProtoResolver implements ProtoResolver {
return PromptPayAccountPayload.fromProto(proto);
case ADVANCED_CASH_ACCOUNT_PAYLOAD:
return AdvancedCashAccountPayload.fromProto(proto);
case TRANSFERWISE_ACCOUNT_PAYLOAD:
return TransferwiseAccountPayload.fromProto(proto);
case INSTANT_CRYPTO_CURRENCY_ACCOUNT_PAYLOAD:
return InstantCryptoCurrencyPayload.fromProto(proto);

View file

@ -144,7 +144,8 @@ public final class TradeStatistics3 implements ProcessOncePersistableNetworkPayl
BLOCK_CHAINS,
PROMPT_PAY,
ADVANCED_CASH,
BLOCK_CHAINS_INSTANT
BLOCK_CHAINS_INSTANT,
TRANSFERWISE
}
@Getter

View file

@ -3393,6 +3393,8 @@ PROMPT_PAY=PromptPay
# suppress inspection "UnusedProperty"
ADVANCED_CASH=Advanced Cash
# suppress inspection "UnusedProperty"
TRANSFERWISE=Transferwise
# suppress inspection "UnusedProperty"
BLOCK_CHAINS_INSTANT=Altcoins Instant
# Deprecated: Cannot be deleted as it would break old trade history entries
@ -3441,6 +3443,8 @@ PROMPT_PAY_SHORT=PromptPay
# suppress inspection "UnusedProperty"
ADVANCED_CASH_SHORT=Advanced Cash
# suppress inspection "UnusedProperty"
TRANSFERWISE_SHORT=Transferwise
# suppress inspection "UnusedProperty"
BLOCK_CHAINS_INSTANT_SHORT=Altcoins Instant
# Deprecated: Cannot be deleted as it would break old trade history entries

View file

@ -0,0 +1,118 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.desktop.components.paymentmethods;
import bisq.desktop.components.InputTextField;
import bisq.desktop.util.FormBuilder;
import bisq.desktop.util.Layout;
import bisq.desktop.util.validation.TransferwiseValidator;
import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.TransferwiseAccount;
import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.payment.payload.TransferwiseAccountPayload;
import bisq.core.util.coin.CoinFormatter;
import bisq.core.util.validation.InputValidator;
import javafx.scene.control.TextField;
import javafx.scene.layout.FlowPane;
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 TransferwiseForm extends PaymentMethodForm {
private final TransferwiseAccount account;
private TransferwiseValidator validator;
private InputTextField emailInputTextField;
public static int addFormForBuyer(GridPane gridPane, int gridRow,
PaymentAccountPayload paymentAccountPayload) {
addCompactTopLabelTextFieldWithCopyIcon(gridPane, ++gridRow, Res.get("payment.email"),
((TransferwiseAccountPayload) paymentAccountPayload).getEmail());
return gridRow;
}
public TransferwiseForm(PaymentAccount paymentAccount, AccountAgeWitnessService accountAgeWitnessService,
TransferwiseValidator validator, InputValidator inputValidator, GridPane gridPane,
int gridRow, CoinFormatter formatter) {
super(paymentAccount, accountAgeWitnessService, inputValidator, gridPane, gridRow, formatter);
this.account = (TransferwiseAccount) paymentAccount;
this.validator = validator;
}
@Override
public void addFormForAddAccount() {
gridRowFrom = gridRow + 1;
emailInputTextField = FormBuilder.addInputTextField(gridPane, ++gridRow, Res.get("payment.email"));
emailInputTextField.setValidator(validator);
emailInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
account.setEmail(newValue.trim());
updateFromInputs();
});
addCurrenciesGrid(true);
addLimitations(false);
addAccountNameTextFieldWithAutoFillToggleButton();
}
private void addCurrenciesGrid(boolean isEditable) {
FlowPane flowPane = FormBuilder.addTopLabelFlowPane(gridPane, ++gridRow,
Res.get("payment.supportedCurrencies"), 20, 20).second;
if (isEditable) {
flowPane.setId("flow-pane-checkboxes-bg");
} else {
flowPane.setId("flow-pane-checkboxes-non-editable-bg");
}
CurrencyUtil.getAllTransferwiseCurrencies().forEach(currency ->
fillUpFlowPaneWithCurrencies(isEditable, flowPane, currency, account));
}
@Override
protected void autoFillNameTextField() {
setAccountNameWithString(emailInputTextField.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()));
TextField field = addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.email"),
account.getEmail()).second;
field.setMouseTransparent(false);
addLimitations(true);
addCurrenciesGrid(false);
}
@Override
public void updateAllInputsValid() {
allInputsValid.set(isAccountNameValid()
&& validator.validate(account.getEmail()).isValid
&& account.getTradeCurrencies().size() > 0);
}
}

View file

@ -31,6 +31,6 @@
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0"/>
</padding>
<columnConstraints>
<ColumnConstraints hgrow="NEVER" minWidth="300.0"/>
<ColumnConstraints hgrow="ALWAYS" minWidth="300.0"/>
</columnConstraints>
</GridPane>

View file

@ -42,6 +42,7 @@ import bisq.desktop.components.paymentmethods.SepaForm;
import bisq.desktop.components.paymentmethods.SepaInstantForm;
import bisq.desktop.components.paymentmethods.SpecificBankForm;
import bisq.desktop.components.paymentmethods.SwishForm;
import bisq.desktop.components.paymentmethods.TransferwiseForm;
import bisq.desktop.components.paymentmethods.USPostalMoneyOrderForm;
import bisq.desktop.components.paymentmethods.UpholdForm;
import bisq.desktop.components.paymentmethods.WeChatPayForm;
@ -67,6 +68,7 @@ import bisq.desktop.util.validation.PopmoneyValidator;
import bisq.desktop.util.validation.PromptPayValidator;
import bisq.desktop.util.validation.RevolutValidator;
import bisq.desktop.util.validation.SwishValidator;
import bisq.desktop.util.validation.TransferwiseValidator;
import bisq.desktop.util.validation.USPostalMoneyOrderValidator;
import bisq.desktop.util.validation.UpholdValidator;
import bisq.desktop.util.validation.WeChatPayValidator;
@ -143,6 +145,7 @@ public class FiatAccountsView extends PaymentAccountsView<GridPane, FiatAccounts
private final F2FValidator f2FValidator;
private final PromptPayValidator promptPayValidator;
private final AdvancedCashValidator advancedCashValidator;
private final TransferwiseValidator transferwiseValidator;
private final CoinFormatter formatter;
private ComboBox<PaymentMethod> paymentMethodComboBox;
private PaymentMethodForm paymentMethodForm;
@ -172,6 +175,7 @@ public class FiatAccountsView extends PaymentAccountsView<GridPane, FiatAccounts
F2FValidator f2FValidator,
PromptPayValidator promptPayValidator,
AdvancedCashValidator advancedCashValidator,
TransferwiseValidator transferwiseValidator,
AccountAgeWitnessService accountAgeWitnessService,
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter) {
super(model, accountAgeWitnessService);
@ -196,6 +200,7 @@ public class FiatAccountsView extends PaymentAccountsView<GridPane, FiatAccounts
this.f2FValidator = f2FValidator;
this.promptPayValidator = promptPayValidator;
this.advancedCashValidator = advancedCashValidator;
this.transferwiseValidator = transferwiseValidator;
this.formatter = formatter;
}
@ -480,6 +485,8 @@ public class FiatAccountsView extends PaymentAccountsView<GridPane, FiatAccounts
return new PromptPayForm(paymentAccount, accountAgeWitnessService, promptPayValidator, inputValidator, root, gridRow, formatter);
case PaymentMethod.ADVANCED_CASH_ID:
return new AdvancedCashForm(paymentAccount, accountAgeWitnessService, advancedCashValidator, inputValidator, root, gridRow, formatter);
case PaymentMethod.TRANSFERWISE_ID:
return new TransferwiseForm(paymentAccount, accountAgeWitnessService, transferwiseValidator, inputValidator, root, gridRow, formatter);
default:
log.error("Not supported PaymentMethod: " + paymentMethod);
return null;

View file

@ -43,6 +43,7 @@ import bisq.desktop.components.paymentmethods.SepaForm;
import bisq.desktop.components.paymentmethods.SepaInstantForm;
import bisq.desktop.components.paymentmethods.SpecificBankForm;
import bisq.desktop.components.paymentmethods.SwishForm;
import bisq.desktop.components.paymentmethods.TransferwiseForm;
import bisq.desktop.components.paymentmethods.USPostalMoneyOrderForm;
import bisq.desktop.components.paymentmethods.UpholdForm;
import bisq.desktop.components.paymentmethods.WeChatPayForm;
@ -306,6 +307,9 @@ public class BuyerStep2View extends TradeStepView {
case PaymentMethod.ADVANCED_CASH_ID:
gridRow = AdvancedCashForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload);
break;
case PaymentMethod.TRANSFERWISE_ID:
gridRow = TransferwiseForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload);
break;
default:
log.error("Not supported PaymentMethod: " + paymentMethodId);
}

View file

@ -0,0 +1,41 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.desktop.util.validation;
import bisq.core.util.validation.InputValidator;
import javax.inject.Inject;
public final class TransferwiseValidator extends InputValidator {
private final EmailValidator emailValidator;
@Inject
public TransferwiseValidator(EmailValidator emailValidator) {
this.emailValidator = emailValidator;
}
@Override
public ValidationResult validate(String input) {
ValidationResult result = super.validate(input);
if (!result.isValid)
return result;
return emailValidator.validate(input);
}
}

View file

@ -931,6 +931,7 @@ message PaymentAccountPayload {
AdvancedCashAccountPayload advanced_cash_account_payload = 26;
InstantCryptoCurrencyAccountPayload instant_crypto_currency_account_payload = 27;
JapanBankAccountPayload japan_bank_account_payload = 28;
TransferwiseAccountPayload Transferwise_account_payload = 29;
}
map<string, string> exclude_from_json_data = 15;
}
@ -1131,6 +1132,10 @@ message AdvancedCashAccountPayload {
string account_nr = 1;
}
message TransferwiseAccountPayload {
string email = 1;
}
///////////////////////////////////////////////////////////////////////////////////////////
// PersistableEnvelope
///////////////////////////////////////////////////////////////////////////////////////////