Skip to content
This repository has been archived by the owner on Jun 17, 2020. It is now read-only.

Add HalCash #144

Merged
merged 8 commits into from
Aug 14, 2018
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions src/main/java/bisq/core/offer/Offer.java
Original file line number Diff line number Diff line change
Expand Up @@ -225,12 +225,11 @@ public void checkTradePriceTolerance(long takersTradePrice) throws TradePriceOut
public Volume getVolumeByAmount(Coin amount) {
Price price = getPrice();
if (price != null && amount != null) {
// try {
return price.getVolumeByAmount(amount);
/* } catch (Throwable t) {
log.error("getVolumeByAmount failed. Error=" + t.getMessage());
return null;
}*/
Volume volumeByAmount = price.getVolumeByAmount(amount);
if (offerPayload.getPaymentMethodId().equals(PaymentMethod.HAL_CASH_ID))
volumeByAmount = OfferUtil.getAdjustedVolumeForHalCash(volumeByAmount);

return volumeByAmount;
} else {
return null;
}
Expand Down
28 changes: 28 additions & 0 deletions src/main/java/bisq/core/offer/OfferUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

import bisq.core.app.BisqEnvironment;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.monetary.Price;
import bisq.core.monetary.Volume;
import bisq.core.provider.fee.FeeService;
import bisq.core.user.Preferences;
import bisq.core.util.CoinUtil;
Expand All @@ -27,6 +29,8 @@

import org.bitcoinj.core.Coin;

import lombok.extern.slf4j.Slf4j;

import javax.annotation.Nullable;

/**
Expand All @@ -36,6 +40,7 @@
* Long-term there could be a GUI-agnostic OfferService which provides these and other functionalities to both the
* GUI and the API.
*/
@Slf4j
public class OfferUtil {

/**
Expand Down Expand Up @@ -131,4 +136,27 @@ public static boolean isBsqForFeeAvailable(BsqWalletService bsqWalletService, @N
availableBalance != null &&
!availableBalance.subtract(makerFee).isNegative();
}

public static Volume getAdjustedVolumeForHalCash(Volume volumeByAmount) {
// EUR has precision 4 and we want multiple of 10 so we divide by 100000 then
// round and multiply with 10
long rounded = Math.max(1, Math.round((double) volumeByAmount.getValue() / 100000d));
return Volume.parse(String.valueOf(rounded * 10), "EUR");
}

public static Coin getAdjustedMinAmountForHalCash(Coin minAmount, Price price) {
// Min amount must result in a volume of min 10 EUR
Volume minVolume = Volume.parse(String.valueOf(10), "EUR");
Coin minAmountByMinVolume = price.getAmountByVolume(minVolume);
if (minAmount.compareTo(minAmountByMinVolume) < 0)
minAmount = minAmountByMinVolume;

// We adjust the minAmount so that the minVolume is a multiple of 10 EUR
minVolume = getAdjustedVolumeForHalCash(price.getVolumeByAmount(minAmount));
minAmount = price.getAmountByVolume(minVolume);

// We want only 4 decimal places
long rounded = Math.round((double) minAmount.value / 10000d) * 10000;
return Coin.valueOf(rounded);
}
}
46 changes: 46 additions & 0 deletions src/main/java/bisq/core/payment/HalCashAccount.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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.FiatCurrency;
import bisq.core.payment.payload.HalCashAccountPayload;
import bisq.core.payment.payload.PaymentAccountPayload;
import bisq.core.payment.payload.PaymentMethod;

import lombok.EqualsAndHashCode;

@EqualsAndHashCode(callSuper = true)
public final class HalCashAccount extends PaymentAccount {
public HalCashAccount() {
super(PaymentMethod.HAL_CASH);
setSingleTradeCurrency(new FiatCurrency("EUR"));
}

@Override
protected PaymentAccountPayload createPayload() {
return new HalCashAccountPayload(paymentMethod.getId(), id);
}

public void setMobileNr(String mobileNr) {
((HalCashAccountPayload) paymentAccountPayload).setMobileNr(mobileNr);
}

public String getMobileNr() {
return ((HalCashAccountPayload) paymentAccountPayload).getMobileNr();
}
}
2 changes: 2 additions & 0 deletions src/main/java/bisq/core/payment/PaymentAccountFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ public static PaymentAccount getPaymentAccount(PaymentMethod paymentMethod) {
return new MoneyGramAccount();
case PaymentMethod.WESTERN_UNION_ID:
return new WesternUnionAccount();
case PaymentMethod.HAL_CASH_ID:
return new HalCashAccount();
case PaymentMethod.F2F_ID:
return new F2FAccount();
default:
Expand Down
102 changes: 102 additions & 0 deletions src/main/java/bisq/core/payment/payload/HalCashAccountPayload.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* 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 io.bisq.generated.protobuffer.PB;

import com.google.protobuf.Message;

import org.springframework.util.CollectionUtils;

import java.nio.charset.Charset;

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;

import javax.annotation.Nullable;

@EqualsAndHashCode(callSuper = true)
@ToString
@Setter
@Getter
@Slf4j
public final class HalCashAccountPayload extends PaymentAccountPayload {
private String mobileNr = "";

public HalCashAccountPayload(String paymentMethod, String id) {
super(paymentMethod, id);
}


///////////////////////////////////////////////////////////////////////////////////////////
// PROTO BUFFER
///////////////////////////////////////////////////////////////////////////////////////////

private HalCashAccountPayload(String paymentMethod, String id,
String mobileNr,
long maxTradePeriod,
@Nullable Map<String, String> excludeFromJsonDataMap) {
super(paymentMethod,
id,
maxTradePeriod,
excludeFromJsonDataMap);
this.mobileNr = mobileNr;
}

@Override
public Message toProtoMessage() {
return getPaymentAccountPayloadBuilder()
.setHalCashAccountPayload(PB.HalCashAccountPayload.newBuilder()
.setMobileNr(mobileNr))
.build();
}

public static HalCashAccountPayload fromProto(PB.PaymentAccountPayload proto) {
return new HalCashAccountPayload(proto.getPaymentMethodId(),
proto.getId(),
proto.getHalCashAccountPayload().getMobileNr(),
proto.getMaxTradePeriod(),
CollectionUtils.isEmpty(proto.getExcludeFromJsonDataMap()) ? null : new HashMap<>(proto.getExcludeFromJsonDataMap()));
}


///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////

@Override
public String getPaymentDetails() {
return "HalCash - Mobile no.: " + mobileNr;
}

@Override
public String getPaymentDetailsForTradePopup() {
return "Mobile no.: " + mobileNr;
}

@Override
public byte[] getAgeWitnessInputData() {
return super.getAgeWitnessInputData(mobileNr.getBytes(Charset.forName("UTF-8")));
}
}
3 changes: 3 additions & 0 deletions src/main/java/bisq/core/payment/payload/PaymentMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public final class PaymentMethod implements PersistablePayload, Comparable {
public static final String CASH_DEPOSIT_ID = "CASH_DEPOSIT";
public static final String MONEY_GRAM_ID = "MONEY_GRAM";
public static final String WESTERN_UNION_ID = "WESTERN_UNION";
public static final String HAL_CASH_ID = "HAL_CASH";
public static final String F2F_ID = "F2F";
public static final String BLOCK_CHAINS_ID = "BLOCK_CHAINS";

Expand Down Expand Up @@ -107,6 +108,7 @@ public final class PaymentMethod implements PersistablePayload, Comparable {
public static PaymentMethod MONEY_GRAM;
public static PaymentMethod WESTERN_UNION;
public static PaymentMethod F2F;
public static PaymentMethod HAL_CASH;
public static PaymentMethod BLOCK_CHAINS;

private static List<PaymentMethod> ALL_VALUES;
Expand Down Expand Up @@ -210,6 +212,7 @@ public static List<PaymentMethod> getAllValues() {
NATIONAL_BANK = new PaymentMethod(NATIONAL_BANK_ID, 4 * DAY, maxTradeLimitMidRisk),
SAME_BANK = new PaymentMethod(SAME_BANK_ID, 2 * DAY, maxTradeLimitMidRisk),
SPECIFIC_BANKS = new PaymentMethod(SPECIFIC_BANKS_ID, 4 * DAY, maxTradeLimitMidRisk),
HAL_CASH = new PaymentMethod(HAL_CASH_ID, DAY, maxTradeLimitLowRisk),
F2F = new PaymentMethod(F2F_ID, 4 * DAY, maxTradeLimitLowRisk),

// Trans national
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/bisq/core/proto/CoreProtoResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import bisq.core.payment.payload.CryptoCurrencyAccountPayload;
import bisq.core.payment.payload.F2FAccountPayload;
import bisq.core.payment.payload.FasterPaymentsAccountPayload;
import bisq.core.payment.payload.HalCashAccountPayload;
import bisq.core.payment.payload.InteracETransferAccountPayload;
import bisq.core.payment.payload.MoneyBeamAccountPayload;
import bisq.core.payment.payload.MoneyGramAccountPayload;
Expand Down Expand Up @@ -128,6 +129,8 @@ public PaymentAccountPayload fromProto(PB.PaymentAccountPayload proto) {
return PerfectMoneyAccountPayload.fromProto(proto);
case SWISH_ACCOUNT_PAYLOAD:
return SwishAccountPayload.fromProto(proto);
case HAL_CASH_ACCOUNT_PAYLOAD:
return HalCashAccountPayload.fromProto(proto);
case U_S_POSTAL_MONEY_ORDER_ACCOUNT_PAYLOAD:
return USPostalMoneyOrderAccountPayload.fromProto(proto);
default:
Expand Down
13 changes: 10 additions & 3 deletions src/main/java/bisq/core/trade/Trade.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@
import bisq.core.monetary.Price;
import bisq.core.monetary.Volume;
import bisq.core.offer.Offer;
import bisq.core.offer.OfferUtil;
import bisq.core.offer.OpenOfferManager;
import bisq.core.payment.AccountAgeWitnessService;
import bisq.core.payment.payload.PaymentMethod;
import bisq.core.proto.CoreProtoResolver;
import bisq.core.trade.protocol.ProcessModel;
import bisq.core.trade.protocol.TradeProtocol;
Expand Down Expand Up @@ -697,10 +699,15 @@ public Date getTakeOfferDate() {

@Nullable
public Volume getTradeVolume() {
if (getTradeAmount() != null && getTradePrice() != null)
return getTradePrice().getVolumeByAmount(getTradeAmount());
else
if (getTradeAmount() != null && getTradePrice() != null) {
Volume volumeByAmount = getTradePrice().getVolumeByAmount(getTradeAmount());
if (offer != null && offer.getPaymentMethod().getId().equals(PaymentMethod.HAL_CASH_ID))
volumeByAmount = OfferUtil.getAdjustedVolumeForHalCash(volumeByAmount);

return volumeByAmount;
} else {
return null;
}
}

public Date getHalfTradePeriodDate() {
Expand Down
20 changes: 18 additions & 2 deletions src/main/resources/i18n/displayStrings.properties
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,10 @@ portfolio.pending.step2_buyer.westernUnionMTCNInfo.headline=Send MTCN and receip
portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=You need to send the MTCN (tracking number) and a photo of the receipt by email to the BTC seller.\n\
The receipt must clearly show the seller''s full name, city, country and the amount. The seller''s email is: {0}.\n\n\
Did you send the MTCN and contract to the seller?

portfolio.pending.step2_buyer.halCashInfo.headline=Send HalCash code
portfolio.pending.step2_buyer.halCashInfo.msg=You need to send a text message with the HalCash code as well as the \
trade ID ({0}) to the BTC seller.\nThe seller''s mobile nr. is {1}.\n\n\
Did you send the code to the seller?
portfolio.pending.step2_buyer.confirmStart.headline=Confirm that you have started the payment
portfolio.pending.step2_buyer.confirmStart.msg=Did you initiate the {0} payment to your trading partner?
portfolio.pending.step2_buyer.confirmStart.yes=Yes, I have started the payment
Expand Down Expand Up @@ -591,6 +594,8 @@ portfolio.pending.step3_seller.westernUnion=The buyer has to send you the MTCN (
The receipt must clearly show your full name, city, country and the amount. Please check your email if you received the MTCN.\n\n\
After closing that popup you will see the BTC buyer's name and address for picking up the money from Western Union.\n\n\
Only confirm receipt after you have successfully picked up the money!
portfolio.pending.step3_seller.halCash=The buyer has to send you the HalCash code as text message. Beside that you will receive a message from HalCash with the required information to withdraw the EUR from a HalCash supporting ATM.\n\n\
After you have picked up the money from the ATM please confirm here the receipt of the payment!

portfolio.pending.step3_seller.bankCheck=\n\nPlease also verify that the sender's name in your bank statement matches that one from the trade contract:\nSender's name: {0}\n\n\
If the name is not the same as the one displayed here, {1}
Expand Down Expand Up @@ -1476,7 +1481,6 @@ popup.warning.noArbitratorSelected.msg=You need to setup at least one arbitrator
popup.warning.notFullyConnected=You need to wait until you are fully connected to the network.\nThat might take up to about 2 minutes at startup.
popup.warning.notSufficientConnectionsToBtcNetwork=You need to wait until you have at least {0} connections to the Bitcoin network.
popup.warning.downloadNotComplete=You need to wait until the download of missing Bitcoin blocks is complete.

popup.warning.removeOffer=Are you sure you want to remove that offer?\nThe maker fee of {0} will be lost if you remove that offer.
popup.warning.tooLargePercentageValue=You cannot set a percentage of 100% or larger.
popup.warning.examplePercentageValue=Please enter a percentage number like \"5.4\" for 5.4%
Expand Down Expand Up @@ -1835,6 +1839,15 @@ payment.moneyGram.info=When using MoneyGram the BTC buyer has to send the Author
The receipt must clearly show the seller's full name, country, state and the amount. The buyer will get displayed the seller's email in the trade process.
payment.westernUnion.info=When using Western Union the BTC buyer has to send the MTCN (tracking number) and a photo of the receipt by email to the BTC seller. \
The receipt must clearly show the seller's full name, city, country and the amount. The buyer will get displayed the seller's email in the trade process.
payment.halCash.info=When using HalCash the BTC buyer need to send the BTC seller the HalCash code via a text message from the mobile phone.\n\n\
Please make sure to not exceed the maximum amount your bank allows you to send with HalCash. \
The min. amount per withdrawal is 10 EUR and the max. amount is 600 EUR. For repeated withdrawals it is \
3000 EUR per receiver per day and 6000 EUR per receiver per month. Please cross check those limits with your \
bank to be sure they use the same limits as stated here.\n\n\
The withdrawal amount must be a multiple of 10 EUR as you cannot withdraw other amounts from an ATM. The \
UI in the create-offer and take-offer screen will adjust the BTC amount so that the EUR amount is correct. You cannot use market \
based price as the EUR amount would be changing with changing prices.\n\n\
In case of a dispute the BTC buyer need to provide the proof that he sent the EUR.
payment.limits.info=Please be aware that all bank transfers carry a certain amount of chargeback risk.\n\
\n\
To mitigate this risk, Bisq sets per-trade limits based on two factors:\n\
Expand Down Expand Up @@ -1921,6 +1934,7 @@ SWISH=Swish
CLEAR_X_CHANGE=Zelle (ClearXchange)
CHASE_QUICK_PAY=Chase QuickPay
INTERAC_E_TRANSFER=Interac e-Transfer
HAL_CASH=HalCash
BLOCK_CHAINS=Altcoins

# suppress inspection "UnusedProperty"
Expand Down Expand Up @@ -1957,6 +1971,8 @@ CHASE_QUICK_PAY_SHORT=Chase QuickPay
# suppress inspection "UnusedProperty"
INTERAC_E_TRANSFER_SHORT=Interac e-Transfer
# suppress inspection "UnusedProperty"
HAL_CASH_SHORT=HalCash
# suppress inspection "UnusedProperty"
BLOCK_CHAINS_SHORT=Altcoins


Expand Down