Adjust CLI to support getting/taking BSQ swaps

Also refactored some of the opt parsers.
This commit is contained in:
ghubstan 2021-11-24 13:10:34 -03:00
parent 3aae052813
commit 0c5c343fe0
No known key found for this signature in database
GPG key ID: E35592D6800A861E
11 changed files with 57 additions and 104 deletions

View file

@ -18,6 +18,7 @@
package bisq.cli; package bisq.cli;
import bisq.proto.grpc.OfferInfo; import bisq.proto.grpc.OfferInfo;
import bisq.proto.grpc.TradeInfo;
import io.grpc.StatusRuntimeException; import io.grpc.StatusRuntimeException;
@ -45,6 +46,7 @@ import static bisq.cli.CurrencyFormat.*;
import static bisq.cli.Method.*; import static bisq.cli.Method.*;
import static bisq.cli.opts.OptLabel.*; import static bisq.cli.opts.OptLabel.*;
import static bisq.cli.table.builder.TableType.*; import static bisq.cli.table.builder.TableType.*;
import static bisq.proto.grpc.GetOfferCategoryReply.OfferCategory.BSQ_SWAP;
import static java.lang.String.format; import static java.lang.String.format;
import static java.lang.System.err; import static java.lang.System.err;
import static java.lang.System.exit; import static java.lang.System.exit;
@ -62,11 +64,11 @@ import bisq.cli.opts.EditOfferOptionParser;
import bisq.cli.opts.GetAddressBalanceOptionParser; import bisq.cli.opts.GetAddressBalanceOptionParser;
import bisq.cli.opts.GetBTCMarketPriceOptionParser; import bisq.cli.opts.GetBTCMarketPriceOptionParser;
import bisq.cli.opts.GetBalanceOptionParser; import bisq.cli.opts.GetBalanceOptionParser;
import bisq.cli.opts.GetOfferOptionParser;
import bisq.cli.opts.GetOffersOptionParser; import bisq.cli.opts.GetOffersOptionParser;
import bisq.cli.opts.GetPaymentAcctFormOptionParser; import bisq.cli.opts.GetPaymentAcctFormOptionParser;
import bisq.cli.opts.GetTradeOptionParser; import bisq.cli.opts.GetTradeOptionParser;
import bisq.cli.opts.GetTransactionOptionParser; import bisq.cli.opts.GetTransactionOptionParser;
import bisq.cli.opts.OfferIdOptionParser;
import bisq.cli.opts.RegisterDisputeAgentOptionParser; import bisq.cli.opts.RegisterDisputeAgentOptionParser;
import bisq.cli.opts.RemoveWalletPasswordOptionParser; import bisq.cli.opts.RemoveWalletPasswordOptionParser;
import bisq.cli.opts.SendBsqOptionParser; import bisq.cli.opts.SendBsqOptionParser;
@ -392,7 +394,7 @@ public class CliMain {
return; return;
} }
case getoffer: { case getoffer: {
var opts = new GetOfferOptionParser(args).parse(); var opts = new OfferIdOptionParser(args).parse();
if (opts.isForHelp()) { if (opts.isForHelp()) {
out.println(client.getMethodHelp(method)); out.println(client.getMethodHelp(method));
return; return;
@ -403,7 +405,7 @@ public class CliMain {
return; return;
} }
case getmyoffer: { case getmyoffer: {
var opts = new GetOfferOptionParser(args).parse(); var opts = new OfferIdOptionParser(args).parse();
if (opts.isForHelp()) { if (opts.isForHelp()) {
out.println(client.getMethodHelp(method)); out.println(client.getMethodHelp(method));
return; return;
@ -446,15 +448,25 @@ public class CliMain {
return; return;
} }
case takeoffer: { case takeoffer: {
var opts = new TakeOfferOptionParser(args).parse(); var offerIdOpt = new OfferIdOptionParser(args).parse();
if (opts.isForHelp()) { if (offerIdOpt.isForHelp()) {
out.println(client.getMethodHelp(method)); out.println(client.getMethodHelp(method));
return; return;
} }
var offerId = opts.getOfferId(); var offerId = offerIdOpt.getOfferId();
var paymentAccountId = opts.getPaymentAccountId(); TradeInfo trade;
var takerFeeCurrencyCode = opts.getTakerFeeCurrencyCode(); // We only send an 'offer-id' param when taking a BsqSwapOffer.
var trade = client.takeOffer(offerId, paymentAccountId, takerFeeCurrencyCode); // Find out what kind of offer is being taken before sending a
// 'takeoffer' request.
var offerCategory = client.getAvailableOfferCategory(offerId);
if (offerCategory.equals(BSQ_SWAP)) {
trade = client.takeBsqSwapOffer(offerId);
} else {
var opts = new TakeOfferOptionParser(args).parse();
var paymentAccountId = opts.getPaymentAccountId();
var takerFeeCurrencyCode = opts.getTakerFeeCurrencyCode();
trade = client.takeOffer(offerId, paymentAccountId, takerFeeCurrencyCode);
}
out.printf("trade %s successfully taken%n", trade.getTradeId()); out.printf("trade %s successfully taken%n", trade.getTradeId());
return; return;
} }
@ -825,7 +837,7 @@ public class CliMain {
stream.format(rowFormat, "", "--currency-code=<currency-code>", ""); stream.format(rowFormat, "", "--currency-code=<currency-code>", "");
stream.println(); stream.println();
stream.format(rowFormat, takeoffer.name(), "--offer-id=<offer-id> \\", "Take offer with id"); stream.format(rowFormat, takeoffer.name(), "--offer-id=<offer-id> \\", "Take offer with id");
stream.format(rowFormat, "", "--payment-account=<payment-account-id>", ""); stream.format(rowFormat, "", "[--payment-account=<payment-account-id>]", "");
stream.format(rowFormat, "", "[--fee-currency=<btc|bsq>]", ""); stream.format(rowFormat, "", "[--fee-currency=<btc|bsq>]", "");
stream.println(); stream.println();
stream.format(rowFormat, gettrade.name(), "--trade-id=<trade-id> \\", "Get trade summary or full contract"); stream.format(rowFormat, gettrade.name(), "--trade-id=<trade-id> \\", "Get trade summary or full contract");

View file

@ -27,7 +27,6 @@ import bisq.proto.grpc.GetVersionRequest;
import bisq.proto.grpc.OfferInfo; import bisq.proto.grpc.OfferInfo;
import bisq.proto.grpc.RegisterDisputeAgentRequest; import bisq.proto.grpc.RegisterDisputeAgentRequest;
import bisq.proto.grpc.StopRequest; import bisq.proto.grpc.StopRequest;
import bisq.proto.grpc.TakeBsqSwapOfferReply;
import bisq.proto.grpc.TakeOfferReply; import bisq.proto.grpc.TakeOfferReply;
import bisq.proto.grpc.TradeInfo; import bisq.proto.grpc.TradeInfo;
import bisq.proto.grpc.TxFeeRateInfo; import bisq.proto.grpc.TxFeeRateInfo;
@ -349,34 +348,18 @@ public final class GrpcClient {
return offersServiceRequest.sortOffersByDate(offers); return offersServiceRequest.sortOffersByDate(offers);
} }
public TakeBsqSwapOfferReply getTakeBsqSwapOfferReply(String offerId,
String paymentAccountId,
String takerFeeCurrencyCode) {
return tradesServiceRequest.getTakeBsqSwapOfferReply(offerId,
paymentAccountId,
takerFeeCurrencyCode);
}
public TakeOfferReply getTakeOfferReply(String offerId, String paymentAccountId, String takerFeeCurrencyCode) { public TakeOfferReply getTakeOfferReply(String offerId, String paymentAccountId, String takerFeeCurrencyCode) {
return tradesServiceRequest.getTakeOfferReply(offerId, paymentAccountId, takerFeeCurrencyCode); return tradesServiceRequest.getTakeOfferReply(offerId, paymentAccountId, takerFeeCurrencyCode);
} }
public TradeInfo takeBsqSwapOffer(String offerId, String paymentAccountId, String takerFeeCurrencyCode) { public TradeInfo takeBsqSwapOffer(String offerId) {
var reply = getTakeBsqSwapOfferReply(offerId, paymentAccountId, takerFeeCurrencyCode); return tradesServiceRequest.takeBsqSwapOffer(offerId);
if (reply.hasBsqSwapTrade())
return reply.getBsqSwapTrade();
else
throw new IllegalStateException(reply.getFailureReason().getDescription());
} }
public TradeInfo takeOffer(String offerId, String paymentAccountId, String takerFeeCurrencyCode) { public TradeInfo takeOffer(String offerId, String paymentAccountId, String takerFeeCurrencyCode) {
return tradesServiceRequest.takeOffer(offerId, paymentAccountId, takerFeeCurrencyCode); return tradesServiceRequest.takeOffer(offerId, paymentAccountId, takerFeeCurrencyCode);
} }
public TradeInfo getBsqSwapTrade(String tradeId) {
return tradesServiceRequest.getBsqSwapTrade(tradeId);
}
public TradeInfo getTrade(String tradeId) { public TradeInfo getTrade(String tradeId) {
return tradesServiceRequest.getTrade(tradeId); return tradesServiceRequest.getTrade(tradeId);
} }

View file

@ -18,14 +18,7 @@
package bisq.cli.opts; package bisq.cli.opts;
import joptsimple.OptionSpec; public class CancelOfferOptionParser extends OfferIdOptionParser implements MethodOpts {
import static bisq.cli.opts.OptLabel.OPT_OFFER_ID;
public class CancelOfferOptionParser extends AbstractMethodOptionParser implements MethodOpts {
final OptionSpec<String> offerIdOpt = parser.accepts(OPT_OFFER_ID, "id of offer to cancel")
.withRequiredArg();
public CancelOfferOptionParser(String[] args) { public CancelOfferOptionParser(String[] args) {
super(args); super(args);
@ -34,12 +27,7 @@ public class CancelOfferOptionParser extends AbstractMethodOptionParser implemen
public CancelOfferOptionParser parse() { public CancelOfferOptionParser parse() {
super.parse(); super.parse();
// Short circuit opt validation if user just wants help. // Super class will short-circuit parsing if help option is present.
if (options.has(helpOpt))
return this;
if (!options.has(offerIdOpt) || options.valueOf(offerIdOpt).isEmpty())
throw new IllegalArgumentException("no offer id specified");
return this; return this;
} }

View file

@ -28,7 +28,7 @@ import static joptsimple.internal.Strings.EMPTY;
public class CreateOfferOptionParser extends AbstractMethodOptionParser implements MethodOpts { public class CreateOfferOptionParser extends AbstractMethodOptionParser implements MethodOpts {
final OptionSpec<String> paymentAccountIdOpt = parser.accepts(OPT_PAYMENT_ACCOUNT, final OptionSpec<String> paymentAccountIdOpt = parser.accepts(OPT_PAYMENT_ACCOUNT,
"id of payment account used for offer") "id of payment account used for offer")
.withRequiredArg() .withRequiredArg()
.defaultsTo(EMPTY); .defaultsTo(EMPTY);

View file

@ -29,7 +29,7 @@ import static java.lang.String.format;
public class CreatePaymentAcctOptionParser extends AbstractMethodOptionParser implements MethodOpts { public class CreatePaymentAcctOptionParser extends AbstractMethodOptionParser implements MethodOpts {
final OptionSpec<String> paymentAcctFormPathOpt = parser.accepts(OPT_PAYMENT_ACCOUNT_FORM, final OptionSpec<String> paymentAcctFormPathOpt = parser.accepts(OPT_PAYMENT_ACCOUNT_FORM,
"path to json payment account form") "path to json payment account form")
.withRequiredArg(); .withRequiredArg();
public CreatePaymentAcctOptionParser(String[] args) { public CreatePaymentAcctOptionParser(String[] args) {

View file

@ -24,7 +24,10 @@ import joptsimple.OptionSpec;
import java.math.BigDecimal; import java.math.BigDecimal;
import static bisq.cli.opts.OptLabel.*; import static bisq.cli.opts.OptLabel.OPT_ENABLE;
import static bisq.cli.opts.OptLabel.OPT_FIXED_PRICE;
import static bisq.cli.opts.OptLabel.OPT_MKT_PRICE_MARGIN;
import static bisq.cli.opts.OptLabel.OPT_TRIGGER_PRICE;
import static bisq.proto.grpc.EditOfferRequest.EditType.*; import static bisq.proto.grpc.EditOfferRequest.EditType.*;
import static java.lang.String.format; import static java.lang.String.format;
@ -32,26 +35,23 @@ import static java.lang.String.format;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
public class EditOfferOptionParser extends AbstractMethodOptionParser implements MethodOpts { public class EditOfferOptionParser extends OfferIdOptionParser implements MethodOpts {
static int OPT_ENABLE_ON = 1; static int OPT_ENABLE_ON = 1;
static int OPT_ENABLE_OFF = 0; static int OPT_ENABLE_OFF = 0;
static int OPT_ENABLE_IGNORED = -1; static int OPT_ENABLE_IGNORED = -1;
final OptionSpec<String> offerIdOpt = parser.accepts(OPT_OFFER_ID, "id of offer to cancel")
.withRequiredArg();
final OptionSpec<String> fixedPriceOpt = parser.accepts(OPT_FIXED_PRICE, "fixed btc price") final OptionSpec<String> fixedPriceOpt = parser.accepts(OPT_FIXED_PRICE, "fixed btc price")
.withOptionalArg() .withOptionalArg()
.defaultsTo("0"); .defaultsTo("0");
final OptionSpec<String> mktPriceMarginOpt = parser.accepts(OPT_MKT_PRICE_MARGIN, final OptionSpec<String> mktPriceMarginOpt = parser.accepts(OPT_MKT_PRICE_MARGIN,
"market btc price margin (%)") "market btc price margin (%)")
.withOptionalArg() .withOptionalArg()
.defaultsTo("0.00"); .defaultsTo("0.00");
final OptionSpec<String> triggerPriceOpt = parser.accepts(OPT_TRIGGER_PRICE, final OptionSpec<String> triggerPriceOpt = parser.accepts(OPT_TRIGGER_PRICE,
"trigger price (applies to mkt price margin based offers)") "trigger price (applies to mkt price margin based offers)")
.withOptionalArg() .withOptionalArg()
.defaultsTo("0"); .defaultsTo("0");
@ -59,7 +59,7 @@ public class EditOfferOptionParser extends AbstractMethodOptionParser implements
// activation state). For this reason, a boolean type is not used (can only be // activation state). For this reason, a boolean type is not used (can only be
// true or false). // true or false).
final OptionSpec<String> enableOpt = parser.accepts(OPT_ENABLE, final OptionSpec<String> enableOpt = parser.accepts(OPT_ENABLE,
"enable or disable offer") "enable or disable offer")
.withOptionalArg() .withOptionalArg()
.ofType(String.class); .ofType(String.class);
@ -72,12 +72,7 @@ public class EditOfferOptionParser extends AbstractMethodOptionParser implements
public EditOfferOptionParser parse() { public EditOfferOptionParser parse() {
super.parse(); super.parse();
// Short circuit opt validation if user just wants help. // Super class will short-circuit parsing if help option is present.
if (options.has(helpOpt))
return this;
if (!options.has(offerIdOpt) || options.valueOf(offerIdOpt).isEmpty())
throw new IllegalArgumentException("no offer id specified");
boolean hasNoEditDetails = !options.has(fixedPriceOpt) boolean hasNoEditDetails = !options.has(fixedPriceOpt)
&& !options.has(mktPriceMarginOpt) && !options.has(mktPriceMarginOpt)
@ -201,10 +196,6 @@ public class EditOfferOptionParser extends AbstractMethodOptionParser implements
return this; return this;
} }
public String getOfferId() {
return options.valueOf(offerIdOpt);
}
public String getFixedPrice() { public String getFixedPrice() {
if (offerEditType.equals(FIXED_PRICE_ONLY) || offerEditType.equals(FIXED_PRICE_AND_ACTIVATION_STATE)) { if (offerEditType.equals(FIXED_PRICE_ONLY) || offerEditType.equals(FIXED_PRICE_AND_ACTIVATION_STATE)) {
return options.has(fixedPriceOpt) ? options.valueOf(fixedPriceOpt) : "0"; return options.has(fixedPriceOpt) ? options.valueOf(fixedPriceOpt) : "0";

View file

@ -25,7 +25,7 @@ import static bisq.cli.opts.OptLabel.OPT_PAYMENT_METHOD_ID;
public class GetPaymentAcctFormOptionParser extends AbstractMethodOptionParser implements MethodOpts { public class GetPaymentAcctFormOptionParser extends AbstractMethodOptionParser implements MethodOpts {
final OptionSpec<String> paymentMethodIdOpt = parser.accepts(OPT_PAYMENT_METHOD_ID, final OptionSpec<String> paymentMethodIdOpt = parser.accepts(OPT_PAYMENT_METHOD_ID,
"id of payment method type used by a payment account") "id of payment method type used by a payment account")
.withRequiredArg(); .withRequiredArg();
public GetPaymentAcctFormOptionParser(String[] args) { public GetPaymentAcctFormOptionParser(String[] args) {

View file

@ -22,16 +22,20 @@ import joptsimple.OptionSpec;
import static bisq.cli.opts.OptLabel.OPT_OFFER_ID; import static bisq.cli.opts.OptLabel.OPT_OFFER_ID;
public class GetOfferOptionParser extends AbstractMethodOptionParser implements MethodOpts { /**
* Superclass for option parsers requiring an offer-id. Avoids a small amount of
* duplicated boilerplate.
*/
public class OfferIdOptionParser extends AbstractMethodOptionParser implements MethodOpts {
final OptionSpec<String> offerIdOpt = parser.accepts(OPT_OFFER_ID, "id of offer to get") final OptionSpec<String> offerIdOpt = parser.accepts(OPT_OFFER_ID, "id of offer")
.withRequiredArg(); .withRequiredArg();
public GetOfferOptionParser(String[] args) { public OfferIdOptionParser(String[] args) {
super(args); super(args);
} }
public GetOfferOptionParser parse() { public OfferIdOptionParser parse() {
super.parse(); super.parse();
// Short circuit opt validation if user just wants help. // Short circuit opt validation if user just wants help.

View file

@ -25,7 +25,7 @@ import static bisq.cli.opts.OptLabel.OPT_TX_FEE_RATE;
public class SetTxFeeRateOptionParser extends AbstractMethodOptionParser implements MethodOpts { public class SetTxFeeRateOptionParser extends AbstractMethodOptionParser implements MethodOpts {
final OptionSpec<String> feeRateOpt = parser.accepts(OPT_TX_FEE_RATE, final OptionSpec<String> feeRateOpt = parser.accepts(OPT_TX_FEE_RATE,
"tx fee rate preference (sats/byte)") "tx fee rate preference (sats/byte)")
.withRequiredArg(); .withRequiredArg();
public SetTxFeeRateOptionParser(String[] args) { public SetTxFeeRateOptionParser(String[] args) {

View file

@ -21,13 +21,9 @@ package bisq.cli.opts;
import joptsimple.OptionSpec; import joptsimple.OptionSpec;
import static bisq.cli.opts.OptLabel.OPT_FEE_CURRENCY; import static bisq.cli.opts.OptLabel.OPT_FEE_CURRENCY;
import static bisq.cli.opts.OptLabel.OPT_OFFER_ID;
import static bisq.cli.opts.OptLabel.OPT_PAYMENT_ACCOUNT; import static bisq.cli.opts.OptLabel.OPT_PAYMENT_ACCOUNT;
public class TakeOfferOptionParser extends AbstractMethodOptionParser implements MethodOpts { public class TakeOfferOptionParser extends OfferIdOptionParser implements MethodOpts {
final OptionSpec<String> offerIdOpt = parser.accepts(OPT_OFFER_ID, "id of offer to take")
.withRequiredArg();
final OptionSpec<String> paymentAccountIdOpt = parser.accepts(OPT_PAYMENT_ACCOUNT, "id of payment account used for trade") final OptionSpec<String> paymentAccountIdOpt = parser.accepts(OPT_PAYMENT_ACCOUNT, "id of payment account used for trade")
.withRequiredArg(); .withRequiredArg();
@ -43,12 +39,7 @@ public class TakeOfferOptionParser extends AbstractMethodOptionParser implements
public TakeOfferOptionParser parse() { public TakeOfferOptionParser parse() {
super.parse(); super.parse();
// Short circuit opt validation if user just wants help. // Super class will short-circuit parsing if help option is present.
if (options.has(helpOpt))
return this;
if (!options.has(offerIdOpt) || options.valueOf(offerIdOpt).isEmpty())
throw new IllegalArgumentException("no offer id specified");
if (!options.has(paymentAccountIdOpt) || options.valueOf(paymentAccountIdOpt).isEmpty()) if (!options.has(paymentAccountIdOpt) || options.valueOf(paymentAccountIdOpt).isEmpty())
throw new IllegalArgumentException("no payment account id specified"); throw new IllegalArgumentException("no payment account id specified");
@ -56,10 +47,6 @@ public class TakeOfferOptionParser extends AbstractMethodOptionParser implements
return this; return this;
} }
public String getOfferId() {
return options.valueOf(offerIdOpt);
}
public String getPaymentAccountId() { public String getPaymentAccountId() {
return options.valueOf(paymentAccountIdOpt); return options.valueOf(paymentAccountIdOpt);
} }

View file

@ -21,8 +21,6 @@ import bisq.proto.grpc.ConfirmPaymentReceivedRequest;
import bisq.proto.grpc.ConfirmPaymentStartedRequest; import bisq.proto.grpc.ConfirmPaymentStartedRequest;
import bisq.proto.grpc.GetTradeRequest; import bisq.proto.grpc.GetTradeRequest;
import bisq.proto.grpc.KeepFundsRequest; import bisq.proto.grpc.KeepFundsRequest;
import bisq.proto.grpc.TakeBsqSwapOfferReply;
import bisq.proto.grpc.TakeBsqSwapOfferRequest;
import bisq.proto.grpc.TakeOfferReply; import bisq.proto.grpc.TakeOfferReply;
import bisq.proto.grpc.TakeOfferRequest; import bisq.proto.grpc.TakeOfferRequest;
import bisq.proto.grpc.TradeInfo; import bisq.proto.grpc.TradeInfo;
@ -40,17 +38,6 @@ public class TradesServiceRequest {
this.grpcStubs = grpcStubs; this.grpcStubs = grpcStubs;
} }
public TakeBsqSwapOfferReply getTakeBsqSwapOfferReply(String offerId,
String paymentAccountId,
String takerFeeCurrencyCode) {
var request = TakeBsqSwapOfferRequest.newBuilder()
.setOfferId(offerId)
.setPaymentAccountId(paymentAccountId)
.setTakerFeeCurrencyCode(takerFeeCurrencyCode)
.build();
return grpcStubs.tradesService.takeBsqSwapOffer(request);
}
public TakeOfferReply getTakeOfferReply(String offerId, String paymentAccountId, String takerFeeCurrencyCode) { public TakeOfferReply getTakeOfferReply(String offerId, String paymentAccountId, String takerFeeCurrencyCode) {
var request = TakeOfferRequest.newBuilder() var request = TakeOfferRequest.newBuilder()
.setOfferId(offerId) .setOfferId(offerId)
@ -60,19 +47,20 @@ public class TradesServiceRequest {
return grpcStubs.tradesService.takeOffer(request); return grpcStubs.tradesService.takeOffer(request);
} }
public TradeInfo takeOffer(String offerId, String paymentAccountId, String takerFeeCurrencyCode) { public TradeInfo takeBsqSwapOffer(String offerId) {
var reply = getTakeOfferReply(offerId, paymentAccountId, takerFeeCurrencyCode); var reply = getTakeOfferReply(offerId, "", "");
if (reply.hasTrade()) if (reply.hasTrade())
return reply.getTrade(); return reply.getTrade();
else else
throw new IllegalStateException(reply.getFailureReason().getDescription()); throw new IllegalStateException(reply.getFailureReason().getDescription());
} }
public TradeInfo getBsqSwapTrade(String tradeId) { public TradeInfo takeOffer(String offerId, String paymentAccountId, String takerFeeCurrencyCode) {
var request = GetTradeRequest.newBuilder() var reply = getTakeOfferReply(offerId, paymentAccountId, takerFeeCurrencyCode);
.setTradeId(tradeId) if (reply.hasTrade())
.build(); return reply.getTrade();
return grpcStubs.tradesService.getBsqSwapTrade(request).getBsqSwapTrade(); else
throw new IllegalStateException(reply.getFailureReason().getDescription());
} }
public TradeInfo getTrade(String tradeId) { public TradeInfo getTrade(String tradeId) {