get trade account payloads over grpc, support crypto account forms

This commit is contained in:
woodser 2022-11-21 08:40:58 -05:00
parent 1f61e82946
commit 0d981a2df6
32 changed files with 292 additions and 295 deletions

View file

@ -157,15 +157,15 @@ public class TakeBuyBTCOfferWithNationalBankAcctTest extends AbstractTradeTest {
assertNotNull(bobsPaymentAccount); assertNotNull(bobsPaymentAccount);
var alicesTrade = aliceClient.getTrade(tradeId); var alicesTrade = aliceClient.getTrade(tradeId);
assertNotEquals("", alicesTrade.getContract().getMakerPaymentAccountPayload().getPaymentDetails()); assertNotEquals(null, alicesTrade.getContract().getMakerPaymentAccountPayload());
assertNotEquals("", alicesTrade.getContract().getTakerPaymentAccountPayload().getPaymentDetails()); assertNotEquals(null, alicesTrade.getContract().getTakerPaymentAccountPayload());
var alicesContractJson = alicesTrade.getContractAsJson(); var alicesContractJson = alicesTrade.getContractAsJson();
verifyJsonContractIncludesBankAccountDetails(alicesContractJson, alicesPaymentAccount); verifyJsonContractIncludesBankAccountDetails(alicesContractJson, alicesPaymentAccount);
verifyJsonContractIncludesBankAccountDetails(alicesContractJson, bobsPaymentAccount); verifyJsonContractIncludesBankAccountDetails(alicesContractJson, bobsPaymentAccount);
var bobsTrade = bobClient.getTrade(tradeId); var bobsTrade = bobClient.getTrade(tradeId);
assertNotEquals("", bobsTrade.getContract().getMakerPaymentAccountPayload().getPaymentDetails()); assertNotEquals(null, bobsTrade.getContract().getMakerPaymentAccountPayload());
assertNotEquals("", bobsTrade.getContract().getTakerPaymentAccountPayload().getPaymentDetails()); assertNotEquals(null, bobsTrade.getContract().getTakerPaymentAccountPayload());
var bobsContractJson = bobsTrade.getContractAsJson(); var bobsContractJson = bobsTrade.getContractAsJson();
verifyJsonContractIncludesBankAccountDetails(bobsContractJson, alicesPaymentAccount); verifyJsonContractIncludesBankAccountDetails(bobsContractJson, alicesPaymentAccount);
verifyJsonContractIncludesBankAccountDetails(bobsContractJson, bobsPaymentAccount); verifyJsonContractIncludesBankAccountDetails(bobsContractJson, bobsPaymentAccount);

View file

@ -246,8 +246,8 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder {
ContractInfo contract = t.getContract(); ContractInfo contract = t.getContract();
boolean isBuyerMakerAndSellerTaker = contract.getIsBuyerMakerAndSellerTaker(); boolean isBuyerMakerAndSellerTaker = contract.getIsBuyerMakerAndSellerTaker();
return isBuyerMakerAndSellerTaker // (is BTC buyer / maker) return isBuyerMakerAndSellerTaker // (is BTC buyer / maker)
? contract.getTakerPaymentAccountPayload().getAddress() ? contract.getTakerPaymentAccountPayload().getCryptoCurrencyAccountPayload().getAddress()
: contract.getMakerPaymentAccountPayload().getAddress(); : contract.getMakerPaymentAccountPayload().getCryptoCurrencyAccountPayload().getAddress();
} else { } else {
return ""; return "";
} }

View file

@ -96,7 +96,7 @@ public class ReflectionUtils {
} }
public static boolean isSetterOnClass(Method setter, Class<?> clazz) { public static boolean isSetterOnClass(Method setter, Class<?> clazz) {
return clazz.equals(setter.getDeclaringClass()); return setter.getDeclaringClass().isAssignableFrom(clazz);
} }
public static String getVisibilityModifierAsString(Field field) { public static String getVisibilityModifierAsString(Field field) {

View file

@ -502,14 +502,18 @@ public class CoreApi {
return paymentAccountsService.getPaymentAccounts(); return paymentAccountsService.getPaymentAccounts();
} }
public List<PaymentMethod> getFiatPaymentMethods() { public List<PaymentMethod> getPaymentMethods() {
return paymentAccountsService.getFiatPaymentMethods(); return paymentAccountsService.getPaymentMethods();
} }
public PaymentAccountForm getPaymentAccountForm(String paymentMethodId) { public PaymentAccountForm getPaymentAccountForm(String paymentMethodId) {
return paymentAccountsService.getPaymentAccountForm(paymentMethodId); return paymentAccountsService.getPaymentAccountForm(paymentMethodId);
} }
public PaymentAccountForm getPaymentAccountForm(PaymentAccount paymentAccount) {
return paymentAccountsService.getPaymentAccountForm(paymentAccount);
}
public PaymentAccount createCryptoCurrencyPaymentAccount(String accountName, public PaymentAccount createCryptoCurrencyPaymentAccount(String accountName,
String currencyCode, String currencyCode,
String address, String address,

View file

@ -19,7 +19,6 @@ package bisq.core.api;
import bisq.core.account.witness.AccountAgeWitnessService; import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.api.model.PaymentAccountForm; import bisq.core.api.model.PaymentAccountForm;
import bisq.core.api.model.PaymentAccountForm;
import bisq.core.api.model.PaymentAccountFormField; import bisq.core.api.model.PaymentAccountFormField;
import bisq.core.locale.CryptoCurrency; import bisq.core.locale.CryptoCurrency;
import bisq.core.locale.CurrencyUtil; import bisq.core.locale.CurrencyUtil;
@ -64,8 +63,6 @@ class CorePaymentAccountsService {
this.user = user; this.user = user;
} }
// Fiat Currency Accounts
PaymentAccount createPaymentAccount(PaymentAccountForm form) { PaymentAccount createPaymentAccount(PaymentAccountForm form) {
PaymentAccount paymentAccount = form.toPaymentAccount(); PaymentAccount paymentAccount = form.toPaymentAccount();
setSelectedTradeCurrency(paymentAccount); // TODO: selected trade currency is function of offer, not payment account payload setSelectedTradeCurrency(paymentAccount); // TODO: selected trade currency is function of offer, not payment account payload
@ -81,12 +78,15 @@ class CorePaymentAccountsService {
private static void setSelectedTradeCurrency(PaymentAccount paymentAccount) { private static void setSelectedTradeCurrency(PaymentAccount paymentAccount) {
TradeCurrency singleTradeCurrency = paymentAccount.getSingleTradeCurrency(); TradeCurrency singleTradeCurrency = paymentAccount.getSingleTradeCurrency();
List<TradeCurrency> tradeCurrencies = paymentAccount.getTradeCurrencies(); List<TradeCurrency> tradeCurrencies = paymentAccount.getTradeCurrencies();
if (singleTradeCurrency != null) return; if (singleTradeCurrency != null) {
else if (tradeCurrencies != null && !tradeCurrencies.isEmpty()) { paymentAccount.setSelectedTradeCurrency(singleTradeCurrency);
if (tradeCurrencies.contains(CurrencyUtil.getDefaultTradeCurrency())) return;
} else if (tradeCurrencies != null && !tradeCurrencies.isEmpty()) {
if (tradeCurrencies.contains(CurrencyUtil.getDefaultTradeCurrency())) {
paymentAccount.setSelectedTradeCurrency(CurrencyUtil.getDefaultTradeCurrency()); paymentAccount.setSelectedTradeCurrency(CurrencyUtil.getDefaultTradeCurrency());
else } else {
paymentAccount.setSelectedTradeCurrency(tradeCurrencies.get(0)); paymentAccount.setSelectedTradeCurrency(tradeCurrencies.get(0));
}
} }
} }
@ -94,9 +94,8 @@ class CorePaymentAccountsService {
return user.getPaymentAccounts(); return user.getPaymentAccounts();
} }
List<PaymentMethod> getFiatPaymentMethods() { List<PaymentMethod> getPaymentMethods() {
return PaymentMethod.getPaymentMethods().stream() return PaymentMethod.getPaymentMethods().stream()
.filter(paymentMethod -> !paymentMethod.isBlockchain())
.sorted(Comparator.comparing(PaymentMethod::getId)) .sorted(Comparator.comparing(PaymentMethod::getId))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@ -105,6 +104,10 @@ class CorePaymentAccountsService {
return PaymentAccountForm.getForm(paymentMethodId); return PaymentAccountForm.getForm(paymentMethodId);
} }
PaymentAccountForm getPaymentAccountForm(PaymentAccount paymentAccount) {
return paymentAccount.toForm();
}
String getPaymentAccountFormAsString(String paymentMethodId) { String getPaymentAccountFormAsString(String paymentMethodId) {
File jsonForm = getPaymentAccountFormFile(paymentMethodId); File jsonForm = getPaymentAccountFormFile(paymentMethodId);
jsonForm.deleteOnExit(); // If just asking for a string, delete the form file. jsonForm.deleteOnExit(); // If just asking for a string, delete the form file.

View file

@ -18,13 +18,13 @@
package bisq.core.api.model; package bisq.core.api.model;
import bisq.common.Payload; import bisq.common.Payload;
import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.proto.CoreProtoResolver;
import java.util.function.Supplier; import java.util.function.Supplier;
import lombok.Getter; import lombok.Getter;
import static bisq.core.api.model.PaymentAccountPayloadInfo.emptyPaymentAccountPayload;
/** /**
* A lightweight Trade Contract constructed from a trade's json contract. * A lightweight Trade Contract constructed from a trade's json contract.
* Many fields in the core Contract are ignored, but can be added as needed. * Many fields in the core Contract are ignored, but can be added as needed.
@ -38,8 +38,8 @@ public class ContractInfo implements Payload {
private final boolean isBuyerMakerAndSellerTaker; private final boolean isBuyerMakerAndSellerTaker;
private final String makerAccountId; private final String makerAccountId;
private final String takerAccountId; private final String takerAccountId;
private final PaymentAccountPayloadInfo makerPaymentAccountPayload; private final PaymentAccountPayload makerPaymentAccountPayload;
private final PaymentAccountPayloadInfo takerPaymentAccountPayload; private final PaymentAccountPayload takerPaymentAccountPayload;
private final String makerPayoutAddressString; private final String makerPayoutAddressString;
private final String takerPayoutAddressString; private final String takerPayoutAddressString;
private final long lockTime; private final long lockTime;
@ -50,8 +50,8 @@ public class ContractInfo implements Payload {
boolean isBuyerMakerAndSellerTaker, boolean isBuyerMakerAndSellerTaker,
String makerAccountId, String makerAccountId,
String takerAccountId, String takerAccountId,
PaymentAccountPayloadInfo makerPaymentAccountPayload, PaymentAccountPayload makerPaymentAccountPayload,
PaymentAccountPayloadInfo takerPaymentAccountPayload, PaymentAccountPayload takerPaymentAccountPayload,
String makerPayoutAddressString, String makerPayoutAddressString,
String takerPayoutAddressString, String takerPayoutAddressString,
long lockTime) { long lockTime) {
@ -77,8 +77,8 @@ public class ContractInfo implements Payload {
false, false,
"", "",
"", "",
emptyPaymentAccountPayload.get(), null,
emptyPaymentAccountPayload.get(), null,
"", "",
"", "",
0); 0);
@ -88,14 +88,15 @@ public class ContractInfo implements Payload {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public static ContractInfo fromProto(bisq.proto.grpc.ContractInfo proto) { public static ContractInfo fromProto(bisq.proto.grpc.ContractInfo proto) {
CoreProtoResolver coreProtoResolver = new CoreProtoResolver();
return new ContractInfo(proto.getBuyerNodeAddress(), return new ContractInfo(proto.getBuyerNodeAddress(),
proto.getSellerNodeAddress(), proto.getSellerNodeAddress(),
proto.getArbitratorNodeAddress(), proto.getArbitratorNodeAddress(),
proto.getIsBuyerMakerAndSellerTaker(), proto.getIsBuyerMakerAndSellerTaker(),
proto.getMakerAccountId(), proto.getMakerAccountId(),
proto.getTakerAccountId(), proto.getTakerAccountId(),
proto.getMakerPaymentAccountPayload() == null ? null : PaymentAccountPayloadInfo.fromProto(proto.getMakerPaymentAccountPayload()), proto.getMakerPaymentAccountPayload() == null ? null : PaymentAccountPayload.fromProto(proto.getMakerPaymentAccountPayload(), coreProtoResolver),
proto.getTakerPaymentAccountPayload() == null ? null : PaymentAccountPayloadInfo.fromProto(proto.getTakerPaymentAccountPayload()), proto.getTakerPaymentAccountPayload() == null ? null : PaymentAccountPayload.fromProto(proto.getTakerPaymentAccountPayload(), coreProtoResolver),
proto.getMakerPayoutAddressString(), proto.getMakerPayoutAddressString(),
proto.getTakerPayoutAddressString(), proto.getTakerPayoutAddressString(),
proto.getLockTime()); proto.getLockTime());
@ -113,8 +114,8 @@ public class ContractInfo implements Payload {
.setMakerPayoutAddressString(makerPayoutAddressString) .setMakerPayoutAddressString(makerPayoutAddressString)
.setTakerPayoutAddressString(takerPayoutAddressString) .setTakerPayoutAddressString(takerPayoutAddressString)
.setLockTime(lockTime); .setLockTime(lockTime);
if (makerPaymentAccountPayload != null) builder.setMakerPaymentAccountPayload(makerPaymentAccountPayload.toProtoMessage()); if (makerPaymentAccountPayload != null) builder.setMakerPaymentAccountPayload((protobuf.PaymentAccountPayload) makerPaymentAccountPayload.toProtoMessage());
if (takerPaymentAccountPayload != null) builder.setTakerPaymentAccountPayload(takerPaymentAccountPayload.toProtoMessage()); if (takerPaymentAccountPayload != null) builder.setTakerPaymentAccountPayload((protobuf.PaymentAccountPayload) takerPaymentAccountPayload.toProtoMessage());
return builder.build(); return builder.build();
} }
} }

View file

@ -17,7 +17,6 @@
package bisq.core.api.model; package bisq.core.api.model;
import static bisq.core.payment.payload.PaymentMethod.getPaymentMethod;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static java.lang.String.format; import static java.lang.String.format;
import static java.lang.System.getProperty; import static java.lang.System.getProperty;
@ -28,15 +27,14 @@ import bisq.common.proto.persistable.PersistablePayload;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PaymentAccountFactory; import bisq.core.payment.PaymentAccountFactory;
import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.PaymentMethod;
import bisq.core.trade.HavenoUtils;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.CaseFormat;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.lang.reflect.Type;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.nio.file.Files; import java.nio.file.Files;
@ -60,11 +58,8 @@ import org.apache.commons.lang3.StringUtils;
@Slf4j @Slf4j
public final class PaymentAccountForm implements PersistablePayload { public final class PaymentAccountForm implements PersistablePayload {
private static final GsonBuilder gsonBuilder = new GsonBuilder()
.setPrettyPrinting()
.serializeNulls();
public enum FormId { public enum FormId {
BLOCK_CHAINS,
REVOLUT, REVOLUT,
SEPA, SEPA,
SEPA_INSTANT, SEPA_INSTANT,
@ -113,6 +108,10 @@ public final class PaymentAccountForm implements PersistablePayload {
return new PaymentAccountForm(FormId.fromProto(proto.getId()), fields); return new PaymentAccountForm(FormId.fromProto(proto.getId()), fields);
} }
public void addField(PaymentAccountFormField field) {
fields.add(field);
}
public String getValue(PaymentAccountFormField.FieldId fieldId) { public String getValue(PaymentAccountFormField.FieldId fieldId) {
for (PaymentAccountFormField field : fields) { for (PaymentAccountFormField field : fields) {
if (field.getId() == fieldId) { if (field.getId() == fieldId) {
@ -122,14 +121,6 @@ public final class PaymentAccountForm implements PersistablePayload {
throw new IllegalArgumentException("Form does not contain field " + fieldId); throw new IllegalArgumentException("Form does not contain field " + fieldId);
} }
/**
* Get a structured form for the given payment method.
*/
public static PaymentAccountForm getForm(String paymentMethodId) {
PaymentAccount paymentAccount = PaymentAccountFactory.getPaymentAccount(PaymentMethod.getPaymentMethod(paymentMethodId));
return paymentAccount.toForm();
}
/** /**
* Convert this form to a PaymentAccount json string. * Convert this form to a PaymentAccount json string.
*/ */
@ -137,7 +128,7 @@ public final class PaymentAccountForm implements PersistablePayload {
Map<String, Object> formMap = new HashMap<String, Object>(); Map<String, Object> formMap = new HashMap<String, Object>();
formMap.put("paymentMethodId", getId().toString()); formMap.put("paymentMethodId", getId().toString());
for (PaymentAccountFormField field : getFields()) { for (PaymentAccountFormField field : getFields()) {
formMap.put(toCamelCase(field.getId().toString()), field.getValue()); formMap.put(HavenoUtils.toCamelCase(field.getId().toString()), field.getValue());
} }
return new Gson().toJson(formMap); return new Gson().toJson(formMap);
} }
@ -146,19 +137,15 @@ public final class PaymentAccountForm implements PersistablePayload {
* Convert this form to a PaymentAccount. * Convert this form to a PaymentAccount.
*/ */
public PaymentAccount toPaymentAccount() { public PaymentAccount toPaymentAccount() {
return toPaymentAccount(toPaymentAccountJsonString()); return PaymentAccount.fromJson(toPaymentAccountJsonString());
} }
/** /**
* De-serialize a PaymentAccount json string into a new PaymentAccount instance. * Get a structured form for the given payment method.
*
* @param paymentAccountJsonString The json data representing a new payment account form.
* @return A populated PaymentAccount subclass instance.
*/ */
public static PaymentAccount toPaymentAccount(String paymentAccountJsonString) { public static PaymentAccountForm getForm(String paymentMethodId) {
Class<? extends PaymentAccount> clazz = getPaymentAccountClassFromJson(paymentAccountJsonString); PaymentAccount paymentAccount = PaymentAccountFactory.getPaymentAccount(PaymentMethod.getPaymentMethod(paymentMethodId));
Gson gson = gsonBuilder.registerTypeAdapter(clazz, new PaymentAccountTypeAdapter(clazz)).create(); return paymentAccount.toForm();
return gson.fromJson(paymentAccountJsonString, clazz);
} }
// ----------------------------- OLD FORM API ----------------------------- // ----------------------------- OLD FORM API -----------------------------
@ -170,7 +157,7 @@ public final class PaymentAccountForm implements PersistablePayload {
* @return A uniquely named tmp file used to define new payment account details. * @return A uniquely named tmp file used to define new payment account details.
*/ */
public static File getPaymentAccountForm(String paymentMethodId) { public static File getPaymentAccountForm(String paymentMethodId) {
PaymentMethod paymentMethod = getPaymentMethod(paymentMethodId); PaymentMethod paymentMethod = PaymentMethod.getPaymentMethod(paymentMethodId);
File file = getTmpJsonFile(paymentMethodId); File file = getTmpJsonFile(paymentMethodId);
try (OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(checkNotNull(file), false), UTF_8)) { try (OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(checkNotNull(file), false), UTF_8)) {
PaymentAccount paymentAccount = PaymentAccountFactory.getPaymentAccount(paymentMethod); PaymentAccount paymentAccount = PaymentAccountFactory.getPaymentAccount(paymentMethod);
@ -193,8 +180,7 @@ public final class PaymentAccountForm implements PersistablePayload {
@SuppressWarnings("unused") @SuppressWarnings("unused")
@VisibleForTesting @VisibleForTesting
public static PaymentAccount toPaymentAccount(File jsonForm) { public static PaymentAccount toPaymentAccount(File jsonForm) {
String jsonString = toJsonString(jsonForm); return PaymentAccount.fromJson(toJsonString(jsonForm));
return toPaymentAccount(jsonString);
} }
public static String toJsonString(File jsonFile) { public static String toJsonString(File jsonFile) {
@ -243,22 +229,4 @@ public final class PaymentAccountForm implements PersistablePayload {
} }
return file; return file;
} }
// -------------------------------- HELPERS -------------------------------
private static String toCamelCase(String underscore) {
return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, underscore);
}
private static Class<? extends PaymentAccount> getPaymentAccountClassFromJson(String json) {
Map<String, Object> jsonMap = gsonBuilder.create().fromJson(json, (Type) Object.class);
String paymentMethodId = checkNotNull((String) jsonMap.get("paymentMethodId"),
format("cannot not find a paymentMethodId in json string: %s", json));
return getPaymentAccountClass(paymentMethodId);
}
private static Class<? extends PaymentAccount> getPaymentAccountClass(String paymentMethodId) {
PaymentMethod paymentMethod = getPaymentMethod(paymentMethodId);
return PaymentAccountFactory.getPaymentAccount(paymentMethod).getClass();
}
} }

View file

@ -40,6 +40,7 @@ import javax.annotation.concurrent.Immutable;
public final class PaymentAccountFormField implements PersistablePayload { public final class PaymentAccountFormField implements PersistablePayload {
public enum FieldId { public enum FieldId {
ADDRESS,
ACCEPTED_COUNTRY_CODES, ACCEPTED_COUNTRY_CODES,
ACCOUNT_ID, ACCOUNT_ID,
ACCOUNT_NAME, ACCOUNT_NAME,
@ -96,8 +97,7 @@ public final class PaymentAccountFormField implements PersistablePayload {
SPECIAL_INSTRUCTIONS, SPECIAL_INSTRUCTIONS,
STATE, STATE,
TRADE_CURRENCIES, TRADE_CURRENCIES,
USER_NAME, USER_NAME;
VIRTUAL_PAYMENT_ADDRESS;
public static PaymentAccountFormField.FieldId fromProto(protobuf.PaymentAccountFormField.FieldId fieldId) { public static PaymentAccountFormField.FieldId fromProto(protobuf.PaymentAccountFormField.FieldId fieldId) {
return ProtoUtil.enumFromProto(PaymentAccountFormField.FieldId.class, fieldId.name()); return ProtoUtil.enumFromProto(PaymentAccountFormField.FieldId.class, fieldId.name());

View file

@ -1,82 +0,0 @@
/*
* This file is part of Haveno.
*
* Haveno 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.
*
* Haveno 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 Haveno. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.core.api.model;
import bisq.core.payment.payload.CryptoCurrencyAccountPayload;
import bisq.core.payment.payload.InstantCryptoCurrencyPayload;
import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.common.Payload;
import java.util.Optional;
import java.util.function.Supplier;
import lombok.Getter;
import javax.annotation.Nullable;
@Getter
public class PaymentAccountPayloadInfo implements Payload {
private final String id;
private final String paymentMethodId;
@Nullable
private final String address;
public PaymentAccountPayloadInfo(String id,
String paymentMethodId,
@Nullable String address) {
this.id = id;
this.paymentMethodId = paymentMethodId;
this.address = address;
}
public static PaymentAccountPayloadInfo toPaymentAccountPayloadInfo(PaymentAccountPayload paymentAccountPayload) {
if (paymentAccountPayload == null) return null;
Optional<String> address = Optional.empty();
if (paymentAccountPayload instanceof CryptoCurrencyAccountPayload)
address = Optional.of(((CryptoCurrencyAccountPayload) paymentAccountPayload).getAddress());
else if (paymentAccountPayload instanceof InstantCryptoCurrencyPayload)
address = Optional.of(((InstantCryptoCurrencyPayload) paymentAccountPayload).getAddress());
return new PaymentAccountPayloadInfo(paymentAccountPayload.getId(),
paymentAccountPayload.getPaymentMethodId(),
address.orElse(""));
}
// For transmitting TradeInfo messages when no contract & payloads are available.
public static Supplier<PaymentAccountPayloadInfo> emptyPaymentAccountPayload = () ->
new PaymentAccountPayloadInfo("", "", "");
///////////////////////////////////////////////////////////////////////////////////////////
// PROTO BUFFER
///////////////////////////////////////////////////////////////////////////////////////////
public static PaymentAccountPayloadInfo fromProto(bisq.proto.grpc.PaymentAccountPayloadInfo proto) {
return new PaymentAccountPayloadInfo(proto.getId(), proto.getPaymentMethodId(), proto.getAddress());
}
@Override
public bisq.proto.grpc.PaymentAccountPayloadInfo toProtoMessage() {
return bisq.proto.grpc.PaymentAccountPayloadInfo.newBuilder()
.setId(id)
.setPaymentMethodId(paymentMethodId)
.setAddress(address != null ? address : "")
.build();
}
}

View file

@ -28,7 +28,6 @@ import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import static bisq.core.api.model.OfferInfo.toOfferInfo; import static bisq.core.api.model.OfferInfo.toOfferInfo;
import static bisq.core.api.model.PaymentAccountPayloadInfo.toPaymentAccountPayloadInfo;
import static bisq.core.util.PriceUtil.reformatMarketPrice; import static bisq.core.util.PriceUtil.reformatMarketPrice;
import static bisq.core.util.VolumeUtil.formatVolume; import static bisq.core.util.VolumeUtil.formatVolume;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
@ -141,8 +140,8 @@ public class TradeInfo implements Payload {
contract.isBuyerMakerAndSellerTaker(), contract.isBuyerMakerAndSellerTaker(),
contract.getMakerAccountId(), contract.getMakerAccountId(),
contract.getTakerAccountId(), contract.getTakerAccountId(),
toPaymentAccountPayloadInfo(trade.getMaker().getPaymentAccountPayload()), trade.getMaker().getPaymentAccountPayload(),
toPaymentAccountPayloadInfo(trade.getTaker().getPaymentAccountPayload()), trade.getTaker().getPaymentAccountPayload(),
contract.getMakerPayoutAddressString(), contract.getMakerPayoutAddressString(),
contract.getTakerPayoutAddressString(), contract.getTakerPayoutAddressString(),
contract.getLockTime()); contract.getLockTime());

View file

@ -611,11 +611,11 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
} }
public Optional<OpenOffer> getOpenOfferById(String offerId) { public Optional<OpenOffer> getOpenOfferById(String offerId) {
return openOffers.stream().filter(e -> e.getId().equals(offerId)).findFirst(); return openOffers.getObservableList().stream().filter(e -> e.getId().equals(offerId)).findFirst();
} }
public Optional<SignedOffer> getSignedOfferById(String offerId) { public Optional<SignedOffer> getSignedOfferById(String offerId) {
return signedOffers.stream().filter(e -> e.getOfferId().equals(offerId)).findFirst(); return signedOffers.getObservableList().stream().filter(e -> e.getOfferId().equals(offerId)).findFirst();
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////

View file

@ -17,7 +17,7 @@
package bisq.core.payment; package bisq.core.payment;
import bisq.core.payment.payload.AssetsAccountPayload; import bisq.core.payment.payload.AssetAccountPayload;
import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.PaymentMethod;
public abstract class AssetAccount extends PaymentAccount { public abstract class AssetAccount extends PaymentAccount {
@ -26,10 +26,10 @@ public abstract class AssetAccount extends PaymentAccount {
} }
public void setAddress(String address) { public void setAddress(String address) {
((AssetsAccountPayload) paymentAccountPayload).setAddress(address); ((AssetAccountPayload) paymentAccountPayload).setAddress(address);
} }
public String getAddress() { public String getAddress() {
return ((AssetsAccountPayload) paymentAccountPayload).getAddress(); return ((AssetAccountPayload) paymentAccountPayload).getAddress();
} }
} }

View file

@ -23,7 +23,6 @@ import bisq.core.payment.payload.CountryBasedPaymentAccountPayload;
import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.PaymentMethod;
import java.util.List; import java.util.List;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NonNull;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -35,17 +34,14 @@ public abstract class CountryBasedPaymentAccount extends PaymentAccount {
@Nullable @Nullable
protected List<Country> acceptedCountries; protected List<Country> acceptedCountries;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor // Constructor
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
protected CountryBasedPaymentAccount(PaymentMethod paymentMethod) { protected CountryBasedPaymentAccount(PaymentMethod paymentMethod) {
super(paymentMethod); super(paymentMethod);
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Getter, Setter // Getter, Setter
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////

View file

@ -33,6 +33,13 @@ import lombok.NonNull;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public final class CryptoCurrencyAccount extends AssetAccount { public final class CryptoCurrencyAccount extends AssetAccount {
private static final List<PaymentAccountFormField.FieldId> INPUT_FIELD_IDS = List.of(
PaymentAccountFormField.FieldId.ACCOUNT_NAME,
PaymentAccountFormField.FieldId.TRADE_CURRENCIES,
PaymentAccountFormField.FieldId.ADDRESS,
PaymentAccountFormField.FieldId.SALT
);
public static final List<TradeCurrency> SUPPORTED_CURRENCIES = new ArrayList<>(CurrencyUtil.getAllSortedCryptoCurrencies()); public static final List<TradeCurrency> SUPPORTED_CURRENCIES = new ArrayList<>(CurrencyUtil.getAllSortedCryptoCurrencies());
public CryptoCurrencyAccount() { public CryptoCurrencyAccount() {
@ -51,6 +58,13 @@ public final class CryptoCurrencyAccount extends AssetAccount {
@Override @Override
public @NonNull List<PaymentAccountFormField.FieldId> getInputFieldIds() { public @NonNull List<PaymentAccountFormField.FieldId> getInputFieldIds() {
throw new RuntimeException("Not implemented"); return INPUT_FIELD_IDS;
}
@Override
protected PaymentAccountFormField getEmptyFormField(PaymentAccountFormField.FieldId fieldId) {
var field = super.getEmptyFormField(fieldId);
if (field.getId() == PaymentAccountFormField.FieldId.TRADE_CURRENCIES) field.setComponent(PaymentAccountFormField.Component.SELECT_ONE);
return field;
} }
} }

View file

@ -19,11 +19,12 @@ package bisq.core.payment;
import bisq.core.api.model.PaymentAccountForm; import bisq.core.api.model.PaymentAccountForm;
import bisq.core.api.model.PaymentAccountFormField; import bisq.core.api.model.PaymentAccountFormField;
import bisq.core.api.model.PaymentAccountFormField.Component;
import bisq.core.api.model.PaymentAccountFormField.FieldId;
import bisq.core.locale.BankUtil; import bisq.core.locale.BankUtil;
import bisq.core.locale.Country; import bisq.core.locale.Country;
import bisq.core.locale.CountryUtil; import bisq.core.locale.CountryUtil;
import bisq.core.locale.CurrencyUtil; import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency; import bisq.core.locale.TradeCurrency;
import bisq.core.payment.payload.PaymentAccountPayload; import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.PaymentMethod;
@ -35,6 +36,7 @@ import bisq.core.payment.validation.EmailValidator;
import bisq.core.payment.validation.IBANValidator; import bisq.core.payment.validation.IBANValidator;
import bisq.core.payment.validation.LengthValidator; import bisq.core.payment.validation.LengthValidator;
import bisq.core.proto.CoreProtoResolver; import bisq.core.proto.CoreProtoResolver;
import bisq.core.trade.HavenoUtils;
import bisq.core.util.validation.InputValidator; import bisq.core.util.validation.InputValidator;
import bisq.core.util.validation.InputValidator.ValidationResult; import bisq.core.util.validation.InputValidator.ValidationResult;
import bisq.common.proto.ProtoUtil; import bisq.common.proto.ProtoUtil;
@ -43,7 +45,9 @@ import bisq.common.util.Utilities;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.function.Function; import java.util.function.Function;
@ -59,12 +63,17 @@ import lombok.extern.slf4j.Slf4j;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import static bisq.core.payment.payload.PaymentMethod.TRANSFERWISE_ID; import static bisq.core.payment.payload.PaymentMethod.TRANSFERWISE_ID;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.Arrays.stream; import static java.util.Arrays.stream;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toList;
import java.lang.reflect.Type;
@EqualsAndHashCode @EqualsAndHashCode
@ToString @ToString
@Getter @Getter
@ -89,6 +98,10 @@ public abstract class PaymentAccount implements PersistablePayload {
@Nullable @Nullable
protected TradeCurrency selectedTradeCurrency; protected TradeCurrency selectedTradeCurrency;
private static final GsonBuilder gsonBuilder = new GsonBuilder()
.setPrettyPrinting()
.serializeNulls();
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor // Constructor
@ -104,6 +117,12 @@ public abstract class PaymentAccount implements PersistablePayload {
paymentAccountPayload = createPayload(); paymentAccountPayload = createPayload();
} }
public void init(PaymentAccountPayload payload) {
id = payload.getId();
creationDate = new Date().getTime();
paymentAccountPayload = payload;
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// PROTO BUFFER // PROTO BUFFER
@ -123,6 +142,19 @@ public abstract class PaymentAccount implements PersistablePayload {
return builder.build(); return builder.build();
} }
public protobuf.PaymentAccount toProtoMessage(protobuf.PaymentAccountPayload paymentAccountPayload) {
checkNotNull(accountName, "accountName must not be null");
protobuf.PaymentAccount.Builder builder = protobuf.PaymentAccount.newBuilder()
.setPaymentMethod(paymentMethod.toProtoMessage())
.setId(id)
.setCreationDate(creationDate)
.setPaymentAccountPayload(paymentAccountPayload)
.setAccountName(accountName)
.addAllTradeCurrencies(ProtoUtil.collectionToProto(tradeCurrencies, protobuf.TradeCurrency.class));
Optional.ofNullable(selectedTradeCurrency).ifPresent(selectedTradeCurrency -> builder.setSelectedTradeCurrency((protobuf.TradeCurrency) selectedTradeCurrency.toProtoMessage()));
return builder.build();
}
public static PaymentAccount fromProto(protobuf.PaymentAccount proto, CoreProtoResolver coreProtoResolver) { public static PaymentAccount fromProto(protobuf.PaymentAccount proto, CoreProtoResolver coreProtoResolver) {
String paymentMethodId = proto.getPaymentMethod().getId(); String paymentMethodId = proto.getPaymentMethod().getId();
List<TradeCurrency> tradeCurrencies = proto.getTradeCurrenciesList().stream() List<TradeCurrency> tradeCurrencies = proto.getTradeCurrenciesList().stream()
@ -286,15 +318,56 @@ public abstract class PaymentAccount implements PersistablePayload {
@NonNull @NonNull
public abstract List<TradeCurrency> getSupportedCurrencies(); public abstract List<TradeCurrency> getSupportedCurrencies();
// ---------------------------- SERIALIZATION -----------------------------
public String toJson() {
Map<String, Object> jsonMap = new HashMap<String, Object>();
if (paymentAccountPayload != null) jsonMap.putAll(gsonBuilder.create().fromJson(paymentAccountPayload.toJson(), (Type) Object.class));
jsonMap.put("accountName", getAccountName());
jsonMap.put("accountId", getId());
if (paymentAccountPayload != null) jsonMap.put("salt", getSaltAsHex());
return gsonBuilder.create().toJson(jsonMap);
}
/**
* Deserialize a PaymentAccount json string into a new PaymentAccount instance.
*
* @param paymentAccountJsonString The json data representing a new payment account form.
* @return A populated PaymentAccount subclass instance.
*/
public static PaymentAccount fromJson(String paymentAccountJsonString) {
Class<? extends PaymentAccount> clazz = getPaymentAccountClassFromJson(paymentAccountJsonString);
Gson gson = gsonBuilder.registerTypeAdapter(clazz, new PaymentAccountTypeAdapter(clazz)).create();
return gson.fromJson(paymentAccountJsonString, clazz);
}
private static Class<? extends PaymentAccount> getPaymentAccountClassFromJson(String json) {
Map<String, Object> jsonMap = gsonBuilder.create().fromJson(json, (Type) Object.class);
String paymentMethodId = checkNotNull((String) jsonMap.get("paymentMethodId"),
String.format("cannot not find a paymentMethodId in json string: %s", json));
return getPaymentAccountClass(paymentMethodId);
}
private static Class<? extends PaymentAccount> getPaymentAccountClass(String paymentMethodId) {
PaymentMethod paymentMethod = PaymentMethod.getPaymentMethod(paymentMethodId);
return PaymentAccountFactory.getPaymentAccount(paymentMethod).getClass();
}
// ------------------------- PAYMENT ACCOUNT FORM ------------------------- // ------------------------- PAYMENT ACCOUNT FORM -------------------------
@NonNull @NonNull
public abstract List<PaymentAccountFormField.FieldId> getInputFieldIds(); public abstract List<PaymentAccountFormField.FieldId> getInputFieldIds();
public PaymentAccountForm toForm() { public PaymentAccountForm toForm() {
// convert to json map
Map<String, Object> jsonMap = gsonBuilder.create().fromJson(toJson(), (Type) Object.class);
// build form
PaymentAccountForm form = new PaymentAccountForm(PaymentAccountForm.FormId.valueOf(paymentMethod.getId())); PaymentAccountForm form = new PaymentAccountForm(PaymentAccountForm.FormId.valueOf(paymentMethod.getId()));
for (PaymentAccountFormField.FieldId fieldId : getInputFieldIds()) { for (PaymentAccountFormField.FieldId fieldId : getInputFieldIds()) {
PaymentAccountFormField field = getEmptyFormField(fieldId); PaymentAccountFormField field = getEmptyFormField(fieldId);
field.setValue((String) jsonMap.get(HavenoUtils.toCamelCase(field.getId().toString())));
form.getFields().add(field); form.getFields().add(field);
} }
return form; return form;
@ -463,8 +536,9 @@ public abstract class PaymentAccount implements PersistablePayload {
case USER_NAME: case USER_NAME:
processValidationResult(new LengthValidator(3, 100).validate(value)); processValidationResult(new LengthValidator(3, 100).validate(value));
break; break;
case VIRTUAL_PAYMENT_ADDRESS: case ADDRESS:
throw new IllegalArgumentException("Not implemented"); processValidationResult(new LengthValidator(10, 150).validate(value)); // TODO: validate crypto address
break;
default: default:
throw new RuntimeException("Unhandled form field: " + fieldId); throw new RuntimeException("Unhandled form field: " + fieldId);
} }
@ -673,8 +747,12 @@ public abstract class PaymentAccount implements PersistablePayload {
field.setMinLength(3); field.setMinLength(3);
field.setMaxLength(100); field.setMaxLength(100);
break; break;
case VIRTUAL_PAYMENT_ADDRESS: case ADDRESS:
throw new IllegalArgumentException("Not implemented"); field.setComponent(PaymentAccountFormField.Component.TEXT);
field.setLabel("Address");
field.setMinLength(10);
field.setMaxLength(150);
break;
default: default:
throw new RuntimeException("Unhandled form field: " + field); throw new RuntimeException("Unhandled form field: " + field);
} }

View file

@ -15,7 +15,7 @@
* along with Haveno. If not, see <http://www.gnu.org/licenses/>. * along with Haveno. If not, see <http://www.gnu.org/licenses/>.
*/ */
package bisq.core.api.model; package bisq.core.payment;
import bisq.core.locale.Country; import bisq.core.locale.Country;
@ -23,9 +23,6 @@ import bisq.core.locale.CountryUtil;
import bisq.core.locale.FiatCurrency; import bisq.core.locale.FiatCurrency;
import bisq.core.locale.Res; import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency; import bisq.core.locale.TradeCurrency;
import bisq.core.payment.CountryBasedPaymentAccount;
import bisq.core.payment.MoneyGramAccount;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.PaymentAccountPayload; import bisq.core.payment.payload.PaymentAccountPayload;
import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapter;
@ -156,13 +153,10 @@ class PaymentAccountTypeAdapter extends TypeAdapter<PaymentAccount> {
field.getType().getSimpleName(), field.getType().getSimpleName(),
field.getName(), field.getName(),
value); value);
String fieldName = field.getName(); String fieldName = field.getName();
out.name(fieldName); out.name(fieldName);
if (fieldName.equals("country")) if (fieldName.equals("country")) out.value("your two letter country code");
out.value("your two letter country code"); else out.value("your " + fieldName.toLowerCase());
else
out.value("your " + fieldName.toLowerCase());
} }
} catch (Exception ex) { } catch (Exception ex) {
String errMsg = format("cannot create a new %s json form", String errMsg = format("cannot create a new %s json form",

View file

@ -24,7 +24,6 @@ import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.PaymentMethod;
import bisq.core.payment.payload.RevolutAccountPayload; import bisq.core.payment.payload.RevolutAccountPayload;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NonNull; import lombok.NonNull;

View file

@ -25,7 +25,6 @@ import bisq.core.payment.payload.PaymentMethod;
import bisq.core.payment.payload.TransferwiseAccountPayload; import bisq.core.payment.payload.TransferwiseAccountPayload;
import java.util.List; import java.util.List;
import java.util.Map;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NonNull; import lombok.NonNull;

View file

@ -34,10 +34,10 @@ import lombok.extern.slf4j.Slf4j;
@Setter @Setter
@Getter @Getter
@Slf4j @Slf4j
public abstract class AssetsAccountPayload extends PaymentAccountPayload { public abstract class AssetAccountPayload extends PaymentAccountPayload {
protected String address = ""; protected String address = "";
protected AssetsAccountPayload(String paymentMethod, String id) { protected AssetAccountPayload(String paymentMethod, String id) {
super(paymentMethod, id); super(paymentMethod, id);
} }
@ -46,7 +46,7 @@ public abstract class AssetsAccountPayload extends PaymentAccountPayload {
// PROTO BUFFER // PROTO BUFFER
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
protected AssetsAccountPayload(String paymentMethod, protected AssetAccountPayload(String paymentMethod,
String id, String id,
String address, String address,
long maxTradePeriod, long maxTradePeriod,

View file

@ -33,7 +33,7 @@ import lombok.extern.slf4j.Slf4j;
@Setter @Setter
@Getter @Getter
@Slf4j @Slf4j
public final class CryptoCurrencyAccountPayload extends AssetsAccountPayload { public final class CryptoCurrencyAccountPayload extends AssetAccountPayload {
public CryptoCurrencyAccountPayload(String paymentMethod, String id) { public CryptoCurrencyAccountPayload(String paymentMethod, String id) {
super(paymentMethod, id); super(paymentMethod, id);

View file

@ -33,7 +33,7 @@ import lombok.extern.slf4j.Slf4j;
@Setter @Setter
@Getter @Getter
@Slf4j @Slf4j
public final class InstantCryptoCurrencyPayload extends AssetsAccountPayload { public final class InstantCryptoCurrencyPayload extends AssetAccountPayload {
public InstantCryptoCurrencyPayload(String paymentMethod, String id) { public InstantCryptoCurrencyPayload(String paymentMethod, String id) {
super(paymentMethod, id); super(paymentMethod, id);

View file

@ -23,9 +23,12 @@ import bisq.common.crypto.Hash;
import bisq.common.proto.network.NetworkPayload; import bisq.common.proto.network.NetworkPayload;
import bisq.common.util.JsonExclude; import bisq.common.util.JsonExclude;
import bisq.common.util.Utilities; import bisq.common.util.Utilities;
import bisq.core.proto.CoreProtoResolver;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
import com.google.gson.GsonBuilder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.HashMap; import java.util.HashMap;
@ -66,6 +69,10 @@ public abstract class PaymentAccountPayload implements NetworkPayload, UsedForTr
@JsonExclude @JsonExclude
protected final Map<String, String> excludeFromJsonDataMap; protected final Map<String, String> excludeFromJsonDataMap;
private static final GsonBuilder gsonBuilder = new GsonBuilder()
.setPrettyPrinting()
.serializeNulls();
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Constructor // Constructor
@ -109,11 +116,18 @@ public abstract class PaymentAccountPayload implements NetworkPayload, UsedForTr
return builder; return builder;
} }
public static PaymentAccountPayload fromProto(protobuf.PaymentAccountPayload proto, CoreProtoResolver coreProtoResolver) {
return coreProtoResolver.fromProto(proto);
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// API // API
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public String toJson() {
return gsonBuilder.create().toJson(this);
}
public abstract String getPaymentDetails(); public abstract String getPaymentDetails();
public abstract String getPaymentDetailsForTradePopup(); public abstract String getPaymentDetailsForTradePopup();

View file

@ -331,6 +331,7 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme
// TODO: delete this override method, which overrides the paymentMethods variable, when all payment methods supported using structured form api, and make paymentMethods private // TODO: delete this override method, which overrides the paymentMethods variable, when all payment methods supported using structured form api, and make paymentMethods private
public static final List<PaymentMethod> getPaymentMethods() { public static final List<PaymentMethod> getPaymentMethods() {
List<String> paymentMethodIds = List.of( List<String> paymentMethodIds = List.of(
BLOCK_CHAINS_ID,
REVOLUT_ID, REVOLUT_ID,
SEPA_ID, SEPA_ID,
SEPA_INSTANT_ID, SEPA_INSTANT_ID,

View file

@ -36,6 +36,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import com.google.common.base.CaseFormat;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
/** /**
@ -225,6 +226,7 @@ public class HavenoUtils {
} }
} }
// TODO: replace with GenUtils.executeTasks()
public static void executeTasks(Collection<Runnable> tasks) { public static void executeTasks(Collection<Runnable> tasks) {
executeTasks(tasks, tasks.size()); executeTasks(tasks, tasks.size());
} }
@ -241,4 +243,8 @@ public class HavenoUtils {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
public static String toCamelCase(String underscore) {
return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, underscore);
}
} }

View file

@ -750,7 +750,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
handleTaskRunnerSuccess(null, null, "SendDepositsConfirmedMessages"); handleTaskRunnerSuccess(null, null, "SendDepositsConfirmedMessages");
}, },
(errorMessage) -> { (errorMessage) -> {
handleTaskRunnerFault(null, null, errorMessage); handleTaskRunnerFault(null, null, "SendDepositsConfirmedMessages", errorMessage);
}))) })))
.executeTasks(true); .executeTasks(true);
awaitTradeLatch(); awaitTradeLatch();

View file

@ -18,7 +18,7 @@
package bisq.core.trade.txproof.xmr; package bisq.core.trade.txproof.xmr;
import bisq.core.monetary.Volume; import bisq.core.monetary.Volume;
import bisq.core.payment.payload.AssetsAccountPayload; import bisq.core.payment.payload.AssetAccountPayload;
import bisq.core.payment.payload.PaymentAccountPayload; import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import bisq.core.trade.txproof.AssetTxProofModel; import bisq.core.trade.txproof.AssetTxProofModel;
@ -26,8 +26,6 @@ import bisq.core.user.AutoConfirmSettings;
import bisq.common.app.DevEnv; import bisq.common.app.DevEnv;
import org.bitcoinj.core.Coin;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import java.util.Date; import java.util.Date;
@ -67,7 +65,7 @@ public class XmrTxProofModel implements AssetTxProofModel {
PaymentAccountPayload sellersPaymentAccountPayload = checkNotNull(trade.getSeller().getPaymentAccountPayload()); PaymentAccountPayload sellersPaymentAccountPayload = checkNotNull(trade.getSeller().getPaymentAccountPayload());
recipientAddress = DevEnv.isDevMode() ? recipientAddress = DevEnv.isDevMode() ?
XmrTxProofModel.DEV_ADDRESS : // For dev testing we need to add the matching address to the dev tx key and dev view key XmrTxProofModel.DEV_ADDRESS : // For dev testing we need to add the matching address to the dev tx key and dev view key
((AssetsAccountPayload) sellersPaymentAccountPayload).getAddress(); ((AssetAccountPayload) sellersPaymentAccountPayload).getAddress();
txHash = trade.getCounterCurrencyTxId(); txHash = trade.getCounterCurrencyTxId();
txKey = trade.getCounterCurrencyExtraData(); txKey = trade.getCounterCurrencyExtraData();
tradeDate = trade.getDate(); tradeDate = trade.getDate();

View file

@ -21,8 +21,10 @@ import bisq.core.api.CoreApi;
import bisq.core.api.model.PaymentAccountForm; import bisq.core.api.model.PaymentAccountForm;
import bisq.core.api.model.PaymentAccountFormField; import bisq.core.api.model.PaymentAccountFormField;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PaymentAccountFactory;
import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.PaymentMethod;
import bisq.core.proto.CoreProtoResolver;
import bisq.proto.grpc.CreateCryptoCurrencyPaymentAccountReply; import bisq.proto.grpc.CreateCryptoCurrencyPaymentAccountReply;
import bisq.proto.grpc.CreateCryptoCurrencyPaymentAccountRequest; import bisq.proto.grpc.CreateCryptoCurrencyPaymentAccountRequest;
import bisq.proto.grpc.CreatePaymentAccountReply; import bisq.proto.grpc.CreatePaymentAccountReply;
@ -104,7 +106,7 @@ class GrpcPaymentAccountsService extends PaymentAccountsImplBase {
public void getPaymentMethods(GetPaymentMethodsRequest req, public void getPaymentMethods(GetPaymentMethodsRequest req,
StreamObserver<GetPaymentMethodsReply> responseObserver) { StreamObserver<GetPaymentMethodsReply> responseObserver) {
try { try {
var paymentMethods = coreApi.getFiatPaymentMethods().stream() var paymentMethods = coreApi.getPaymentMethods().stream()
.map(PaymentMethod::toProtoMessage) .map(PaymentMethod::toProtoMessage)
.collect(Collectors.toList()); .collect(Collectors.toList());
var reply = GetPaymentMethodsReply.newBuilder() var reply = GetPaymentMethodsReply.newBuilder()
@ -120,7 +122,16 @@ class GrpcPaymentAccountsService extends PaymentAccountsImplBase {
public void getPaymentAccountForm(GetPaymentAccountFormRequest req, public void getPaymentAccountForm(GetPaymentAccountFormRequest req,
StreamObserver<GetPaymentAccountFormReply> responseObserver) { StreamObserver<GetPaymentAccountFormReply> responseObserver) {
try { try {
var form = coreApi.getPaymentAccountForm(req.getPaymentMethodId()); PaymentAccountForm form = null;
if (req.getPaymentMethodId().isEmpty()) {
PaymentAccount account = PaymentAccountFactory.getPaymentAccount(PaymentMethod.getPaymentMethod(req.getPaymentAccountPayload().getPaymentMethodId()));
account.setAccountName("tmp");
account.init(PaymentAccountPayload.fromProto(req.getPaymentAccountPayload(), new CoreProtoResolver()));
account.setAccountName(null);
form = coreApi.getPaymentAccountForm(account);
} else {
form = coreApi.getPaymentAccountForm(req.getPaymentMethodId());
}
var reply = GetPaymentAccountFormReply.newBuilder() var reply = GetPaymentAccountFormReply.newBuilder()
.setPaymentAccountForm(form.toProtoMessage()) .setPaymentAccountForm(form.toProtoMessage())
.build(); .build();

View file

@ -31,7 +31,7 @@ import bisq.core.locale.TradeCurrency;
import bisq.core.payment.AssetAccount; import bisq.core.payment.AssetAccount;
import bisq.core.payment.InstantCryptoCurrencyAccount; import bisq.core.payment.InstantCryptoCurrencyAccount;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.AssetsAccountPayload; import bisq.core.payment.payload.AssetAccountPayload;
import bisq.core.payment.payload.PaymentAccountPayload; import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.payment.validation.AltCoinAddressValidator; import bisq.core.payment.validation.AltCoinAddressValidator;
import bisq.core.util.coin.CoinFormatter; import bisq.core.util.coin.CoinFormatter;
@ -71,7 +71,7 @@ public class AssetsForm extends PaymentMethodForm {
PaymentAccountPayload paymentAccountPayload, PaymentAccountPayload paymentAccountPayload,
String labelTitle) { String labelTitle) {
addCompactTopLabelTextFieldWithCopyIcon(gridPane, ++gridRow, labelTitle, addCompactTopLabelTextFieldWithCopyIcon(gridPane, ++gridRow, labelTitle,
((AssetsAccountPayload) paymentAccountPayload).getAddress()); ((AssetAccountPayload) paymentAccountPayload).getAddress());
return gridRow; return gridRow;
} }

View file

@ -87,7 +87,7 @@ import bisq.core.network.MessageState;
import bisq.core.offer.Offer; import bisq.core.offer.Offer;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PaymentAccountUtil; import bisq.core.payment.PaymentAccountUtil;
import bisq.core.payment.payload.AssetsAccountPayload; import bisq.core.payment.payload.AssetAccountPayload;
import bisq.core.payment.payload.CashByMailAccountPayload; import bisq.core.payment.payload.CashByMailAccountPayload;
import bisq.core.payment.payload.CashDepositAccountPayload; import bisq.core.payment.payload.CashDepositAccountPayload;
import bisq.core.payment.payload.F2FAccountPayload; import bisq.core.payment.payload.F2FAccountPayload;
@ -548,7 +548,7 @@ public class BuyerStep2View extends TradeStepView {
} else { } else {
showConfirmPaymentStartedPopup(); showConfirmPaymentStartedPopup();
} }
} else if (sellersPaymentAccountPayload instanceof AssetsAccountPayload && isXmrTrade()) { } else if (sellersPaymentAccountPayload instanceof AssetAccountPayload && isXmrTrade()) {
SetXmrTxKeyWindow setXmrTxKeyWindow = new SetXmrTxKeyWindow(); SetXmrTxKeyWindow setXmrTxKeyWindow = new SetXmrTxKeyWindow();
setXmrTxKeyWindow setXmrTxKeyWindow
.actionButtonText(Res.get("portfolio.pending.step2_buyer.confirmStart.headline")) .actionButtonText(Res.get("portfolio.pending.step2_buyer.confirmStart.headline"))
@ -623,7 +623,7 @@ public class BuyerStep2View extends TradeStepView {
String fees = Res.get("portfolio.pending.step2_buyer.fees"); String fees = Res.get("portfolio.pending.step2_buyer.fees");
String id = trade.getShortId(); String id = trade.getShortId();
String amount = VolumeUtil.formatVolumeWithCode(trade.getVolume()); String amount = VolumeUtil.formatVolumeWithCode(trade.getVolume());
if (paymentAccountPayload instanceof AssetsAccountPayload) { if (paymentAccountPayload instanceof AssetAccountPayload) {
message += Res.get("portfolio.pending.step2_buyer.altcoin", message += Res.get("portfolio.pending.step2_buyer.altcoin",
getCurrencyName(trade), getCurrencyName(trade),
amount); amount);

View file

@ -24,7 +24,6 @@ import bisq.desktop.components.indicator.TxConfidenceIndicator;
import bisq.desktop.main.overlays.popups.Popup; import bisq.desktop.main.overlays.popups.Popup;
import bisq.desktop.main.portfolio.pendingtrades.PendingTradesViewModel; import bisq.desktop.main.portfolio.pendingtrades.PendingTradesViewModel;
import bisq.desktop.main.portfolio.pendingtrades.steps.TradeStepView; import bisq.desktop.main.portfolio.pendingtrades.steps.TradeStepView;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil; import bisq.desktop.util.GUIUtil;
import bisq.desktop.util.Layout; import bisq.desktop.util.Layout;
@ -32,7 +31,7 @@ import bisq.core.locale.Res;
import bisq.core.payment.PaymentAccount; import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PaymentAccountUtil; import bisq.core.payment.PaymentAccountUtil;
import bisq.core.payment.payload.AmazonGiftCardAccountPayload; import bisq.core.payment.payload.AmazonGiftCardAccountPayload;
import bisq.core.payment.payload.AssetsAccountPayload; import bisq.core.payment.payload.AssetAccountPayload;
import bisq.core.payment.payload.BankAccountPayload; import bisq.core.payment.payload.BankAccountPayload;
import bisq.core.payment.payload.CashByMailAccountPayload; import bisq.core.payment.payload.CashByMailAccountPayload;
import bisq.core.payment.payload.CashDepositAccountPayload; import bisq.core.payment.payload.CashDepositAccountPayload;
@ -226,13 +225,13 @@ public class SellerStep3View extends TradeStepView {
.map(PaymentAccount::getAccountName) .map(PaymentAccount::getAccountName)
.orElse(""); .orElse("");
if (myPaymentAccountPayload instanceof AssetsAccountPayload) { if (myPaymentAccountPayload instanceof AssetAccountPayload) {
if (myPaymentDetails.isEmpty()) { if (myPaymentDetails.isEmpty()) {
// Not expected // Not expected
myPaymentDetails = ((AssetsAccountPayload) myPaymentAccountPayload).getAddress(); myPaymentDetails = ((AssetAccountPayload) myPaymentAccountPayload).getAddress();
} }
peersPaymentDetails = peersPaymentAccountPayload != null ? peersPaymentDetails = peersPaymentAccountPayload != null ?
((AssetsAccountPayload) peersPaymentAccountPayload).getAddress() : "NA"; ((AssetAccountPayload) peersPaymentAccountPayload).getAddress() : "NA";
myTitle = Res.get("portfolio.pending.step3_seller.yourAddress", currencyName); myTitle = Res.get("portfolio.pending.step3_seller.yourAddress", currencyName);
peersTitle = Res.get("portfolio.pending.step3_seller.buyersAddress", currencyName); peersTitle = Res.get("portfolio.pending.step3_seller.buyersAddress", currencyName);
} else { } else {
@ -374,7 +373,7 @@ public class SellerStep3View extends TradeStepView {
if (!DevEnv.isDevMode() && DontShowAgainLookup.showAgain(key)) { if (!DevEnv.isDevMode() && DontShowAgainLookup.showAgain(key)) {
PaymentAccountPayload paymentAccountPayload = model.dataModel.getSellersPaymentAccountPayload(); PaymentAccountPayload paymentAccountPayload = model.dataModel.getSellersPaymentAccountPayload();
String message = Res.get("portfolio.pending.step3_seller.onPaymentReceived.part1", getCurrencyName(trade)); String message = Res.get("portfolio.pending.step3_seller.onPaymentReceived.part1", getCurrencyName(trade));
if (!(paymentAccountPayload instanceof AssetsAccountPayload)) { if (!(paymentAccountPayload instanceof AssetAccountPayload)) {
Optional<String> optionalHolderName = getOptionalHolderName(); Optional<String> optionalHolderName = getOptionalHolderName();
if (optionalHolderName.isPresent()) { if (optionalHolderName.isPresent()) {
message += Res.get("portfolio.pending.step3_seller.onPaymentReceived.name", optionalHolderName.get()); message += Res.get("portfolio.pending.step3_seller.onPaymentReceived.name", optionalHolderName.get());
@ -406,8 +405,8 @@ public class SellerStep3View extends TradeStepView {
String tradeVolumeWithCode = VolumeUtil.formatVolumeWithCode(trade.getVolume()); String tradeVolumeWithCode = VolumeUtil.formatVolumeWithCode(trade.getVolume());
String currencyName = getCurrencyName(trade); String currencyName = getCurrencyName(trade);
String part1 = Res.get("portfolio.pending.step3_seller.part", currencyName); String part1 = Res.get("portfolio.pending.step3_seller.part", currencyName);
if (paymentAccountPayload instanceof AssetsAccountPayload) { if (paymentAccountPayload instanceof AssetAccountPayload) {
String address = ((AssetsAccountPayload) paymentAccountPayload).getAddress(); String address = ((AssetAccountPayload) paymentAccountPayload).getAddress();
String explorerOrWalletString = isXmrTrade() ? String explorerOrWalletString = isXmrTrade() ?
Res.get("portfolio.pending.step3_seller.altcoin.wallet", currencyName) : Res.get("portfolio.pending.step3_seller.altcoin.wallet", currencyName) :
Res.get("portfolio.pending.step3_seller.altcoin.explorer", currencyName); Res.get("portfolio.pending.step3_seller.altcoin.explorer", currencyName);

View file

@ -595,6 +595,7 @@ message GetPaymentMethodsReply {
message GetPaymentAccountFormRequest { message GetPaymentAccountFormRequest {
string payment_method_id = 1; string payment_method_id = 1;
PaymentAccountPayload payment_account_payload = 2;
} }
message GetPaymentAccountFormReply { message GetPaymentAccountFormReply {
@ -864,8 +865,8 @@ message ContractInfo {
bool is_buyer_maker_and_seller_taker = 5; bool is_buyer_maker_and_seller_taker = 5;
string maker_account_id = 6; string maker_account_id = 6;
string taker_account_id = 7; string taker_account_id = 7;
PaymentAccountPayloadInfo maker_payment_account_payload = 8; PaymentAccountPayload maker_payment_account_payload = 8;
PaymentAccountPayloadInfo taker_payment_account_payload = 9; PaymentAccountPayload taker_payment_account_payload = 9;
string maker_payout_address_string = 10; string maker_payout_address_string = 10;
string taker_payout_address_string = 11; string taker_payout_address_string = 11;
uint64 lock_time = 12; uint64 lock_time = 12;
@ -873,13 +874,6 @@ message ContractInfo {
string arbitrator_node_address = 100; string arbitrator_node_address = 100;
} }
message PaymentAccountPayloadInfo {
string id = 1;
string payment_method_id = 2;
string address = 3;
string payment_details = 4;
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Transactions // Transactions
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////

View file

@ -1997,18 +1997,19 @@ message MockPayload {
message PaymentAccountForm { message PaymentAccountForm {
enum FormId { enum FormId {
REVOLUT = 0; BLOCK_CHAINS = 0;
SEPA = 1; REVOLUT = 1;
SEPA_INSTANT = 2; SEPA = 2;
TRANSFERWISE = 3; SEPA_INSTANT = 3;
CLEAR_X_CHANGE = 4; TRANSFERWISE = 4;
SWIFT = 5; CLEAR_X_CHANGE = 5;
F2F = 6; SWIFT = 6;
STRIKE = 7; F2F = 7;
MONEY_GRAM = 8; STRIKE = 8;
FASTER_PAYMENTS = 9; MONEY_GRAM = 9;
UPHOLD = 10; FASTER_PAYMENTS = 10;
PAXUM = 11; UPHOLD = 11;
PAXUM = 12;
} }
FormId id = 1; FormId id = 1;
repeated PaymentAccountFormField fields = 2; repeated PaymentAccountFormField fields = 2;
@ -2016,64 +2017,64 @@ message PaymentAccountForm {
message PaymentAccountFormField { message PaymentAccountFormField {
enum FieldId { enum FieldId {
ACCEPTED_COUNTRY_CODES = 0; ADDRESS = 0;
ACCOUNT_ID = 1; ACCEPTED_COUNTRY_CODES = 1;
ACCOUNT_NAME = 2; ACCOUNT_ID = 2;
ACCOUNT_NR = 3; ACCOUNT_NAME = 3;
ACCOUNT_OWNER = 4; ACCOUNT_NR = 4;
ACCOUNT_TYPE = 5; ACCOUNT_OWNER = 5;
ANSWER = 6; ACCOUNT_TYPE = 6;
BANK_ACCOUNT_NAME = 7; ANSWER = 7;
BANK_ACCOUNT_NUMBER = 8; BANK_ACCOUNT_NAME = 8;
BANK_ACCOUNT_TYPE = 9; BANK_ACCOUNT_NUMBER = 9;
BANK_ADDRESS = 10; BANK_ACCOUNT_TYPE = 10;
BANK_BRANCH = 11; BANK_ADDRESS = 11;
BANK_BRANCH_CODE = 12; BANK_BRANCH = 12;
BANK_BRANCH_NAME = 13; BANK_BRANCH_CODE = 13;
BANK_CODE = 14; BANK_BRANCH_NAME = 14;
BANK_COUNTRY_CODE = 15; BANK_CODE = 15;
BANK_ID = 16; BANK_COUNTRY_CODE = 16;
BANK_NAME = 17; BANK_ID = 17;
BANK_SWIFT_CODE = 18; BANK_NAME = 18;
BENEFICIARY_ACCOUNT_NR = 19; BANK_SWIFT_CODE = 19;
BENEFICIARY_ADDRESS = 20; BENEFICIARY_ACCOUNT_NR = 20;
BENEFICIARY_CITY = 21; BENEFICIARY_ADDRESS = 21;
BENEFICIARY_NAME = 22; BENEFICIARY_CITY = 22;
BENEFICIARY_PHONE = 23; BENEFICIARY_NAME = 23;
BIC = 24; BENEFICIARY_PHONE = 24;
BRANCH_ID = 25; BIC = 25;
CITY = 26; BRANCH_ID = 26;
CONTACT = 27; CITY = 27;
COUNTRY = 28; CONTACT = 28;
EMAIL = 29; COUNTRY = 29;
EMAIL_OR_MOBILE_NR = 30; EMAIL = 30;
EXTRA_INFO = 31; EMAIL_OR_MOBILE_NR = 31;
HOLDER_ADDRESS = 32; EXTRA_INFO = 32;
HOLDER_EMAIL = 33; HOLDER_ADDRESS = 33;
HOLDER_NAME = 34; HOLDER_EMAIL = 34;
HOLDER_TAX_ID = 35; HOLDER_NAME = 35;
IBAN = 36; HOLDER_TAX_ID = 36;
IFSC = 37; IBAN = 37;
INTERMEDIARY_ADDRESS = 38; IFSC = 38;
INTERMEDIARY_BRANCH = 39; INTERMEDIARY_ADDRESS = 39;
INTERMEDIARY_COUNTRY_CODE = 40; INTERMEDIARY_BRANCH = 40;
INTERMEDIARY_NAME = 41; INTERMEDIARY_COUNTRY_CODE = 41;
INTERMEDIARY_SWIFT_CODE = 42; INTERMEDIARY_NAME = 42;
MOBILE_NR = 43; INTERMEDIARY_SWIFT_CODE = 43;
NATIONAL_ACCOUNT_ID = 44; MOBILE_NR = 44;
PAYID = 45; NATIONAL_ACCOUNT_ID = 45;
PIX_KEY = 46; PAYID = 46;
POSTAL_ADDRESS = 47; PIX_KEY = 47;
PROMPT_PAY_ID = 48; POSTAL_ADDRESS = 48;
QUESTION = 49; PROMPT_PAY_ID = 49;
REQUIREMENTS = 50; QUESTION = 50;
SALT = 51; REQUIREMENTS = 51;
SORT_CODE = 52; SALT = 52;
SPECIAL_INSTRUCTIONS = 53; SORT_CODE = 53;
STATE = 54; SPECIAL_INSTRUCTIONS = 54;
TRADE_CURRENCIES = 55; STATE = 55;
USER_NAME = 56; TRADE_CURRENCIES = 56;
VIRTUAL_PAYMENT_ADDRESS = 57; USER_NAME = 57;
} }
enum Component { enum Component {
TEXT = 0; TEXT = 0;