Complete API support for BSQ/BTC trade pair

- Finished API server's verify bsq payment impl.
- Added verifybsqsenttoaddress method to CLI.
- Added verifybsqsenttoaddress-help.txt to server.
- Fixed client getoffers, getmyoffers to work with BSQ offers.
This commit is contained in:
ghubstan 2021-04-15 14:21:25 -03:00
parent 8ac30262c0
commit e96da16df8
No known key found for this signature in database
GPG Key ID: E35592D6800A861E
7 changed files with 186 additions and 20 deletions

View File

@ -76,6 +76,7 @@ import bisq.cli.opts.SetWalletPasswordOptionParser;
import bisq.cli.opts.SimpleMethodOptionParser;
import bisq.cli.opts.TakeOfferOptionParser;
import bisq.cli.opts.UnlockWalletOptionParser;
import bisq.cli.opts.VerifyBsqSentToAddressOptionParser;
import bisq.cli.opts.WithdrawFundsOptionParser;
/**
@ -264,6 +265,23 @@ public class CliMain {
txInfo.getTxId());
return;
}
case verifybsqsenttoaddress: {
var opts = new VerifyBsqSentToAddressOptionParser(args).parse();
if (opts.isForHelp()) {
out.println(client.getMethodHelp(method));
return;
}
var address = opts.getAddress();
var amount = opts.getAmount();
verifyStringIsValidDecimal(OPT_AMOUNT, amount);
var bsqWasSent = client.verifyBsqSentToAddress(address, amount);
out.printf("%s bsq has %s been sent to address %s%n",
amount,
bsqWasSent ? "" : "not",
address);
return;
}
case gettxfeerate: {
if (new SimpleMethodOptionParser(args).parse().isForHelp()) {
out.println(client.getMethodHelp(method));
@ -511,7 +529,7 @@ public class CliMain {
jsonString = new String(Files.readAllBytes(paymentAccountForm));
} catch (IOException e) {
throw new IllegalStateException(
format("could not read %s", paymentAccountForm.toString()));
format("could not read %s", paymentAccountForm));
}
var paymentAccount = client.createPaymentAccount(jsonString);
out.println("payment account saved");
@ -717,6 +735,9 @@ public class CliMain {
stream.format(rowFormat, "", "[--tx-fee-rate=<sats/byte>]", "");
stream.format(rowFormat, "", "[--memo=<\"memo\">]", "");
stream.println();
stream.format(rowFormat, verifybsqsenttoaddress.name(), "--address=<bsq-address> --amount=<bsq-amount>",
"Verify amount was sent to BSQ wallet address");
stream.println();
stream.format(rowFormat, gettxfeerate.name(), "", "Get current tx fee rate in sats/byte");
stream.println();
stream.format(rowFormat, settxfeerate.name(), "--tx-fee-rate=<sats/byte>", "Set custom tx fee rate in sats/byte");

View File

@ -0,0 +1,35 @@
/*
* 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.cli;
import java.util.ArrayList;
import java.util.List;
class CryptoCurrencyUtil {
public static boolean isSupportedCryptoCurrency(String currencyCode) {
return getSupportedCryptoCurrencies().contains(currencyCode.toUpperCase());
}
public static List<String> getSupportedCryptoCurrencies() {
final List<String> result = new ArrayList<>();
result.add("BSQ");
result.sort(String::compareTo);
return result;
}
}

View File

@ -73,6 +73,7 @@ import java.util.List;
import lombok.extern.slf4j.Slf4j;
import static bisq.cli.CryptoCurrencyUtil.isSupportedCryptoCurrency;
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;
import static protobuf.OfferPayload.Direction.BUY;
@ -286,16 +287,20 @@ public final class GrpcClient {
}
public List<OfferInfo> getOffers(String direction, String currencyCode) {
var request = GetOffersRequest.newBuilder()
.setDirection(direction)
.setCurrencyCode(currencyCode)
.build();
return grpcStubs.offersService.getOffers(request).getOffersList();
if (isSupportedCryptoCurrency(currencyCode)) {
return getCryptoCurrencyOffers(direction, currencyCode);
} else {
var request = GetOffersRequest.newBuilder()
.setDirection(direction)
.setCurrencyCode(currencyCode)
.build();
return grpcStubs.offersService.getOffers(request).getOffersList();
}
}
public List<OfferInfo> getBsqOffers(String direction) {
public List<OfferInfo> getCryptoCurrencyOffers(String direction, String currencyCode) {
return getOffers(direction, "BTC").stream()
.filter(o -> o.getBaseCurrencyCode().equals("BSQ"))
.filter(o -> o.getBaseCurrencyCode().equalsIgnoreCase(currencyCode))
.collect(toList());
}
@ -313,22 +318,26 @@ public final class GrpcClient {
public List<OfferInfo> getBsqOffersSortedByDate() {
ArrayList<OfferInfo> offers = new ArrayList<>();
offers.addAll(getBsqOffers(BUY.name()));
offers.addAll(getBsqOffers(SELL.name()));
offers.addAll(getCryptoCurrencyOffers(BUY.name(), "BSQ"));
offers.addAll(getCryptoCurrencyOffers(SELL.name(), "BSQ"));
return sortOffersByDate(offers);
}
public List<OfferInfo> getMyOffers(String direction, String currencyCode) {
var request = GetMyOffersRequest.newBuilder()
.setDirection(direction)
.setCurrencyCode(currencyCode)
.build();
return grpcStubs.offersService.getMyOffers(request).getOffersList();
if (isSupportedCryptoCurrency(currencyCode)) {
return getMyCryptoCurrencyOffers(direction, currencyCode);
} else {
var request = GetMyOffersRequest.newBuilder()
.setDirection(direction)
.setCurrencyCode(currencyCode)
.build();
return grpcStubs.offersService.getMyOffers(request).getOffersList();
}
}
public List<OfferInfo> getMyBsqOffers(String direction) {
public List<OfferInfo> getMyCryptoCurrencyOffers(String direction, String currencyCode) {
return getMyOffers(direction, "BTC").stream()
.filter(o -> o.getBaseCurrencyCode().equals("BSQ"))
.filter(o -> o.getBaseCurrencyCode().equalsIgnoreCase(currencyCode))
.collect(toList());
}
@ -346,8 +355,8 @@ public final class GrpcClient {
public List<OfferInfo> getMyBsqOffersSortedByDate() {
ArrayList<OfferInfo> offers = new ArrayList<>();
offers.addAll(getMyBsqOffers(BUY.name()));
offers.addAll(getMyBsqOffers(SELL.name()));
offers.addAll(getMyCryptoCurrencyOffers(BUY.name(), "BSQ"));
offers.addAll(getMyCryptoCurrencyOffers(SELL.name(), "BSQ"));
return sortOffersByDate(offers);
}

View File

@ -49,6 +49,7 @@ public enum Method {
removewalletpassword,
sendbsq,
sendbtc,
verifybsqsenttoaddress,
settxfeerate,
setwalletpassword,
takeoffer,

View File

@ -50,7 +50,7 @@ public class CreatePaymentAcctOptionParser extends AbstractMethodOptionParser im
if (!path.toFile().exists())
throw new IllegalStateException(
format("json payment account form '%s' could not be found",
path.toString()));
path));
return this;
}

View File

@ -0,0 +1,61 @@
/*
* 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.cli.opts;
import joptsimple.OptionSpec;
import static bisq.cli.opts.OptLabel.OPT_ADDRESS;
import static bisq.cli.opts.OptLabel.OPT_AMOUNT;
public class VerifyBsqSentToAddressOptionParser extends AbstractMethodOptionParser implements MethodOpts {
final OptionSpec<String> addressOpt = parser.accepts(OPT_ADDRESS, "receiving bsq address")
.withRequiredArg();
final OptionSpec<String> amountOpt = parser.accepts(OPT_AMOUNT, "amount of bsq received")
.withRequiredArg();
public VerifyBsqSentToAddressOptionParser(String[] args) {
super(args);
}
public VerifyBsqSentToAddressOptionParser parse() {
super.parse();
// Short circuit opt validation if user just wants help.
if (options.has(helpOpt))
return this;
if (!options.has(addressOpt) || options.valueOf(addressOpt).isEmpty())
throw new IllegalArgumentException("no bsq address specified");
if (!options.has(amountOpt) || options.valueOf(amountOpt).isEmpty())
throw new IllegalArgumentException("no bsq amount specified");
return this;
}
public String getAddress() {
return options.valueOf(addressOpt);
}
public String getAmount() {
return options.valueOf(amountOpt);
}
}

View File

@ -0,0 +1,39 @@
verifybsqsenttoaddress
NAME
----
verifybsqsenttoaddress - verify BSQ sent to wallet address
SYNOPSIS
--------
verifybsqsenttoaddress
--address=<bsq-address>
--amount=<bsq-amount>
DESCRIPTION
-----------
Verify an exact amount of BSQ was sent to a specific Bisq wallet's BSQ address.
Receipt of BSQ to a BSQ (altcoin) payment account address should always be verified
before a BSQ seller sends a confirmpaymentreceived message for a BSQ/BTC trade.
Warning: The verification result should be considered a false positive if a BSQ wallet
address has received the same amount of BSQ in more than one transaction. A way to
avoid this problem is to use different BSQ payment accounts for different trades, so
the payment account receiving address will vary from trade to trade. Another way is to
slightly vary your offer amounts and BSQ prices (if you are the maker), to make sure the
received BSQ amounts vary from trade to trade. Doing all of the above further reduces
the chance of a false positive. Another step is to check your BSQ wallet balance when
you verify BSQ has been received to an address.
OPTIONS
-------
--address
The receiving BSQ address.
--amount
The amount of BSQ received.
EXAMPLES
--------
Verify 500.00 BSQ was sent to address Bn3PCQgRwhkrGnaMp1RYwt9tFwL51YELqne:
$ ./bisq-cli --password=xyz --port=9998 verifybsqsenttoaddress --address=Bn3PCQgRwhkrGnaMp1RYwt9tFwL51YELqne --amount=500.00