diff --git a/apitest/docs/api-beta-test-guide.md b/apitest/docs/api-beta-test-guide.md
index c3ff01b724e..5eb57131f02 100644
--- a/apitest/docs/api-beta-test-guide.md
+++ b/apitest/docs/api-beta-test-guide.md
@@ -17,9 +17,9 @@ option adjustments to compensate.
**Shell**: Bash
-**Java SDK**: Version 10, 11, 12 or 15
+**Java SDK**: Version 11 - 15 (src and class generation version 11)
-**Bitcoin-Core**: Version 0.19, 0.20, or 0.21
+**Bitcoin-Core**: Version 0.19 - 22
**Git Client**
@@ -372,6 +372,22 @@ The `trade-simulation.sh` script options that would generate the previous `creat
$ apitest/scripts/trade-simulation.sh -d sell -c jp -m 0.5 -a 0.125
```
+The `createoffer` command can also be used to create BSQ swap offers, where trade execution is performed immediately
+after a BSQ swap offer is taken. To swap 0.5 BTC for BSQ at a price of 0.00005 BSQ per 1 BTC:
+```
+$ ./bisq-cli --password=xyz --port=9998 createoffer \
+ --swap=true \
+ --direction=BUY \
+ --amount=0.5 \
+ --currency-code=BSQ \
+ --fixed-price=0.00005
+```
+
+The `bsqswap-simulation.sh` script options that would generate the previous `createoffer` example is:
+```
+$ apitest/scripts/bsqswap-simulation.sh -d buy -a 0.5 -f 0.00005
+```
+
### Browsing Your Own Offers
There are different commands to browse available offers you can take, and offers you created.
@@ -530,7 +546,7 @@ A CLI user browses available offers with the getoffers command. For example, th
$ ./bisq-cli --password=xyz --port=9998 getoffers --direction=SELL --currency-code=EUR
```
-And takes one of the available offers with an EUR payment account ( id `fe20cdbd-22be-4b8a-a4b6-d2608ff09d6e`)
+Then takes one of the available offers with an EUR payment account ( id `fe20cdbd-22be-4b8a-a4b6-d2608ff09d6e`)
with the `takeoffer` command:
```
$ ./bisq-cli --password=xyz --port=9998 takeoffer \
@@ -538,8 +554,10 @@ $ ./bisq-cli --password=xyz --port=9998 takeoffer \
--payment-account=fe20cdbd-22be-4b8a-a4b6-d2608ff09d6e \
--fee-currency=btc
```
-The taken offer will be used to create a trade contract. The next section describes how to use the Api to execute
-the trade.
+Depending on the offer type, the taken offer will be used to (1) create a trade contract, or (2) execute a BSQ swap.
+
+The next section describes how to use the Api to execute a trade. The following Completing a BSQ Swap Trade
+section explains how to use the `takeoffer` command to complete a BSQ swap.
### Completing Trade Protocol
@@ -598,6 +616,14 @@ $ ./bisq-cli --password=xyz --port=9998 keepfunds --trade-id=
$ ./bisq-cli --password=xyz --port=9999 withdrawfunds --trade-id= --address= [--memo=<"memo">]
```
+### Completing a BSQ Swap Trade
+
+The `takeoffer` command will immediately perform the BSQ swap, assuming both sides' wallets have sufficient BTC and
+BSQ to cover the trade amount, and maker or taker fee. It takes one argument: `--offer-id=`:
+```
+$ ./bisq-cli --password=xyz --port=9998 takeoffer --offer-id=Xge8b2e2-51b6-3TOOB-z748-3ebd29c2kj99
+```
+
## Shutting Down Test Harness
The test harness should cleanly shutdown all the background apps in proper order after entering ^C.
diff --git a/apitest/docs/build-run.md b/apitest/docs/build-run.md
index ba9149e2383..d877b71f429 100644
--- a/apitest/docs/build-run.md
+++ b/apitest/docs/build-run.md
@@ -4,7 +4,7 @@ The Java based API runs on Linux and OSX.
## Mainnet
-To build from the source, clone the github repository found at `https://github.com/bisq-network/bisq`,
+To build from the source, clone the GitHub repository found at `https://github.com/bisq-network/bisq`,
and build with gradle:
$ ./gradlew clean build
diff --git a/apitest/scripts/bsqswap-simulation-utils.sh b/apitest/scripts/bsqswap-simulation-utils.sh
new file mode 100755
index 00000000000..d0f4787b744
--- /dev/null
+++ b/apitest/scripts/bsqswap-simulation-utils.sh
@@ -0,0 +1,79 @@
+#! /bin/bash
+
+# This file must be sourced by the driver script.
+
+source "$APITEST_SCRIPTS_HOME/trade-simulation-env.sh"
+source "$APITEST_SCRIPTS_HOME/trade-simulation-utils.sh"
+
+gencreatebsqswapoffercommand() {
+ PORT="$1"
+ CMD="$CLI_BASE --port=$PORT createoffer"
+ CMD+=" --swap=true"
+ CMD+=" --direction=$DIRECTION"
+ CMD+=" --amount=$AMOUNT"
+ CMD+=" --fixed-price=$FIXED_PRICE"
+ CMD+=" --currency-code=$CURRENCY_CODE"
+ echo "$CMD"
+}
+
+createbsqswapoffer() {
+ CREATE_OFFER_CMD="$1"
+ OFFER_DESC=$($CREATE_OFFER_CMD)
+
+ # If the CLI command exited with an error, print the CLI error, and
+ # return from this function now, passing the error status code to the caller.
+ commandalert $? "Could not create offer."
+
+ OFFER_DETAIL=$(echo -e "$OFFER_DESC" | sed -n '2p')
+ NEW_OFFER_ID=$(echo -e "$OFFER_DETAIL" | awk '{print $NF}')
+ echo "$NEW_OFFER_ID"
+}
+
+executebsqswap() {
+ # Bob list available BSQ offers. (If a v1 BSQ offer is picked this simulation will break.)
+ printdate "Bob looking at $DIRECTION $CURRENCY_CODE offers."
+ CMD="$CLI_BASE --port=$BOB_PORT getoffers --direction=$DIRECTION --currency-code=$CURRENCY_CODE"
+ printdate "BOB CLI: $CMD"
+ OFFERS=$($CMD)
+ exitoncommandalert $?
+ echo "$OFFERS"
+ printbreak
+
+ OFFER_ID=$(getfirstofferid "$BOB_PORT")
+ exitoncommandalert $?
+ printdate "First BSQ offer found: $OFFER_ID"
+
+ # Take Alice's BSQ swap offer.
+ CMD="$CLI_BASE --port=$BOB_PORT takeoffer --offer-id=$OFFER_ID"
+ printdate "BOB CLI: $CMD"
+ TRADE=$($CMD)
+ commandalert $? "Could not take BSQ swap offer."
+ # Print the takeoffer command's console output.
+ printdate "$TRADE"
+ printbreak
+
+ # Generate 1 btc block
+ printdate "Generating 1 btc block after BSQ swap execution."
+ genbtcblocks 1 2
+ printbreak
+
+ printdate "BSQ swap trade $OFFER_ID complete."
+ printbreak
+
+ printdate "Alice looking at her trade with id $OFFER_ID."
+ CMD="$CLI_BASE --port=$ALICE_PORT gettrade --trade-id=$OFFER_ID"
+ printdate "ALICE CLI: $CMD"
+ GETTRADE_CMD_OUTPUT=$(gettrade "$CMD")
+ exitoncommandalert $?
+ echo "$GETTRADE_CMD_OUTPUT"
+ printbreak
+
+ printdate "Bob looking at his trade with id $OFFER_ID."
+ CMD="$CLI_BASE --port=$BOB_PORT gettrade --trade-id=$OFFER_ID"
+ printdate "BOB CLI: $CMD"
+ GETTRADE_CMD_OUTPUT=$(gettrade "$CMD")
+ exitoncommandalert $?
+ echo "$GETTRADE_CMD_OUTPUT"
+ printbreak
+}
+
diff --git a/apitest/scripts/bsqswap-simulation.sh b/apitest/scripts/bsqswap-simulation.sh
new file mode 100755
index 00000000000..482a0fc40c7
--- /dev/null
+++ b/apitest/scripts/bsqswap-simulation.sh
@@ -0,0 +1,90 @@
+#! /bin/bash
+
+# Demonstrates a bsq <-> btc swap trade using the API CLI with a local regtest bitcoin node.
+#
+# Prerequisites:
+#
+# - Linux or OSX with bash, Java 11-15 (JDK language compatibility 11), and bitcoin-core (v0.19 - v22).
+#
+# - Bisq must be fully built with apitest dao setup files installed.
+# Build command: `./gradlew clean build :apitest:installDaoSetup`
+#
+# - All supporting nodes must be run locally, in dev/dao/regtest mode:
+# bitcoind, seednode, arbdaemon, alicedaemon, bobdaemon
+#
+# These should be run using the apitest harness. From the root project dir, run:
+# `$ ./bisq-apitest --apiPassword=xyz --supportingApps=bitcoind,seednode,arbdaemon,alicedaemon,bobdaemon --shutdownAfterTests=false`
+#
+# Usage:
+#
+# This script must be run from the root of the project, e.g.:
+#
+# `$ apitest/scripts/bsqswap-simulation.sh -d buy -f 0.00005 -a 0.125`
+#
+# Script options: -d -c -f -a
+#
+# Examples:
+#
+# Create and take a bsq swap offer to buy 0.05 btc at a fixed-price of 0.00005 bsq (per 1 btc):
+#
+# `$ apitest/scripts/bsqswap-simulation.sh -d buy -a 0.05 -f 0.00005`
+#
+# Create and take a bsq swap offer to buy 1 btc at a fixed-price of 0.00005 bsq (per 1 btc):
+#
+# `$ apitest/scripts/bsqswap-simulation.sh -d buy -a 1 -f 0.0005`
+
+export APP_BASE_NAME=$(basename "$0")
+export APP_HOME=$(pwd -P)
+export APITEST_SCRIPTS_HOME="$APP_HOME/apitest/scripts"
+
+source "$APITEST_SCRIPTS_HOME/trade-simulation-env.sh"
+source "$APITEST_SCRIPTS_HOME/trade-simulation-utils.sh"
+source "$APITEST_SCRIPTS_HOME/bsqswap-simulation-utils.sh"
+
+checksetup
+parsebsqswaporderopts "$@"
+
+printdate "Started $APP_BASE_NAME with parameters:"
+printbsqswapscriptparams
+printbreak
+
+# Alice creates a bsq swap offer.
+printdate "Alice creating BSQ swap offer: $DIRECTION $AMOUNT BTC for BSQ at fixed price of $FIXED_PRICE BTC per 1 BSQ."
+CMD=$(gencreatebsqswapoffercommand "$ALICE_PORT" "$ALICE_ACCT_ID")
+printdate "ALICE CLI: $CMD"
+OFFER_ID=$(createbsqswapoffer "$CMD")
+exitoncommandalert $?
+printdate "Alice created bsq swap offer with id: $OFFER_ID."
+printbreak
+sleeptraced 2
+
+# Show Alice's new bsq swap offer.
+printdate "Alice looking at her new $DIRECTION $CURRENCY_CODE offer."
+CMD="$CLI_BASE --port=$ALICE_PORT getmyoffer --offer-id=$OFFER_ID"
+printdate "ALICE CLI: $CMD"
+OFFER=$($CMD)
+exitoncommandalert $?
+echo "$OFFER"
+printbreak
+sleeptraced 2
+
+# Generate 1 btc block.
+printdate "Generating 1 btc block after publishing Alice's offer."
+genbtcblocks 1 1
+printbreak
+
+# Execute the BSQ swap.
+executebsqswap
+exitoncommandalert $?
+printbreak
+
+# Get balances after trade completion.
+printdate "Bob & Alice's balances after BSQ swap trade."
+printdate "ALICE CLI:"
+printbalances "$ALICE_PORT"
+printbreak
+printdate "BOB CLI:"
+printbalances "$BOB_PORT"
+printbreak
+
+exit 0
diff --git a/apitest/scripts/limit-order-simulation.sh b/apitest/scripts/limit-order-simulation.sh
index db37d8ab949..3ee50b63dda 100755
--- a/apitest/scripts/limit-order-simulation.sh
+++ b/apitest/scripts/limit-order-simulation.sh
@@ -6,7 +6,7 @@
#
# Prerequisites:
#
-# - Linux or OSX with bash, Java 10, or Java 11-12 (JDK language compatibility 10), and bitcoin-core (v0.19, v0.20, v0.21).
+# - Linux or OSX with bash, Java 11-15 (JDK language compatibility 11), and bitcoin-core (v0.19 - v22).
#
# - Bisq must be fully built with apitest dao setup files installed.
# Build command: `./gradlew clean build :apitest:installDaoSetup`
diff --git a/apitest/scripts/rolling-offer-simulation.sh b/apitest/scripts/rolling-offer-simulation.sh
index c269940e646..3bbfba4eb5f 100755
--- a/apitest/scripts/rolling-offer-simulation.sh
+++ b/apitest/scripts/rolling-offer-simulation.sh
@@ -10,7 +10,7 @@
#
# Prerequisites:
#
-# - Linux or OSX with bash, Java 10, or Java 11-12 (JDK language compatibility 10), and bitcoin-core (v0.19, v0.20, v0.21).
+# - Linux or OSX with bash, Java 11-15 (JDK language compatibility 11), and bitcoin-core (v0.19 - v22).
#
# - Bisq must be fully built with apitest dao setup files installed.
# Build command: `./gradlew clean build :apitest:installDaoSetup`
diff --git a/apitest/scripts/trade-simulation-env.sh b/apitest/scripts/trade-simulation-env.sh
index 45fc385e072..e3735fe2a99 100755
--- a/apitest/scripts/trade-simulation-env.sh
+++ b/apitest/scripts/trade-simulation-env.sh
@@ -179,6 +179,41 @@ parselimitorderopts() {
fi
}
+parsebsqswaporderopts() {
+ usage() {
+ echo "Usage: $0 [-d buy|sell] [-f ] [-a ]" 1>&2
+ exit 1;
+ }
+
+ local OPTIND o d f a
+ while getopts "d:f:a:" o; do
+ case "${o}" in
+ d) d=$(echo "${OPTARG}" | tr '[:lower:]' '[:upper:]')
+ ((d == "BUY" || d == "SELL")) || usage
+ export DIRECTION=${d}
+ ;;
+ f) f=${OPTARG}
+ export FIXED_PRICE=${f}
+ ;;
+ a) a=${OPTARG}
+ export AMOUNT=${a}
+ ;;
+ *) usage ;;
+ esac
+ done
+ shift $((OPTIND-1))
+
+ if [ -z "${d}" ] || [ -z "${a}" ]; then
+ usage
+ fi
+
+ if [ -z "${f}" ] ; then
+ usage
+ fi
+
+ export CURRENCY_CODE="BSQ"
+}
+
checkbitcoindrunning() {
# There may be a '+' char in the path and we have to escape it for pgrep.
if [[ $APP_HOME == *"+"* ]]; then
@@ -310,3 +345,9 @@ printscriptparams() {
echo " WAIT = $WAIT"
fi
}
+
+printbsqswapscriptparams() {
+ echo " DIRECTION = $DIRECTION"
+ echo " FIXED_PRICE = $FIXED_PRICE"
+ echo " AMOUNT = $AMOUNT"
+}
diff --git a/apitest/scripts/trade-simulation-utils.sh b/apitest/scripts/trade-simulation-utils.sh
index 6b146222619..4b63c3a7c5a 100755
--- a/apitest/scripts/trade-simulation-utils.sh
+++ b/apitest/scripts/trade-simulation-utils.sh
@@ -457,11 +457,10 @@ delayconfirmpaymentreceived() {
printbreak
}
-# This is a large function that should be broken up if it ever makes sense to not treat a trade
-# execution simulation as an bsq swap operation. But we are not testing api methods here, just
-# demonstrating how to use them to get through the trade protocol. It should work for any trade
-# between Bob & Alice, as long as Alice is maker, Bob is taker, and the offer to be taken is the
-# first displayed in Bob's getoffers command output.
+# This is a large function that might be split into smaller functions. But we are not testing
+# api methods here, just demonstrating how to use them to get through the V1 trade protocol with
+# the CLI. It should work for any trade between Bob & Alice, as long as Alice is maker, Bob is
+# taker, and the offer to be taken is the first displayed in Bob's getoffers command output.
executetrade() {
# Bob list available offers.
printdate "BOB $BOB_ROLE: Looking at $DIRECTION $CURRENCY_CODE offers."
@@ -477,7 +476,7 @@ executetrade() {
printdate "First offer found: $OFFER_ID"
# Take Alice's offer.
- CMD="$CLI_BASE --port=$BOB_PORT takeoffer --offer-id=$OFFER_ID --payment-account=$BOB_ACCT_ID --fee-currency=bsq"
+ CMD="$CLI_BASE --port=$BOB_PORT takeoffer --offer-id=$OFFER_ID --payment-account=$BOB_ACCT_ID --fee-currency=BSQ"
printdate "BOB CLI: $CMD"
TRADE=$($CMD)
commandalert $? "Could not take offer."
diff --git a/apitest/scripts/trade-simulation.sh b/apitest/scripts/trade-simulation.sh
index 5aa540bf71a..0af66535aa5 100755
--- a/apitest/scripts/trade-simulation.sh
+++ b/apitest/scripts/trade-simulation.sh
@@ -1,13 +1,13 @@
#! /bin/bash
-# Runs fiat <-> btc trading scenarios using the API CLI with a local regtest bitcoin node.
+# Demonstrates a fiat <-> btc trade using the API CLI with a local regtest bitcoin node.
#
# A country code argument is used to create a country based face to face payment account for the simulated
# trade, and the maker's face to face payment account's currency code is used when creating the offer.
#
# Prerequisites:
#
-# - Linux or OSX with bash, Java 10, or Java 11-12 (JDK language compatibility 10), and bitcoin-core (v0.19, v0.20, or v0.21).
+# - Linux or OSX with bash, Java 11-15 (JDK language compatibility 11), and bitcoin-core (v0.19 - v22).
#
# - Bisq must be fully built with apitest dao setup files installed.
# Build command: `./gradlew clean build :apitest:installDaoSetup`
@@ -26,15 +26,16 @@
#
# `$ apitest/scripts/trade-simulation.sh -d buy -c fr -m 3.00 -a 0.125`
#
-# Script options: -d -c -m - f -a
+# Script options: -d -c -m -f -a
#
# Examples:
#
-# Create a buy/eur offer to buy 0.125 btc at a mkt-price-margin of 0%, using an Italy face to face payment account:
+# Create and take a buy/eur offer to buy 0.125 btc at a mkt-price-margin of 0%, using an Italy face to face
+# payment account:
#
# `$ apitest/scripts/trade-simulation.sh -d buy -c it -m 0.00 -a 0.125`
#
-# Create a sell/eur offer to sell 0.125 btc at a fixed-price of 38,000 euros, using a France face to face
+# Create and take a sell/eur offer to sell 0.125 btc at a fixed-price of 38,000 euros, using a France face to face
# payment account:
#
# `$ apitest/scripts/trade-simulation.sh -d sell -c fr -f 38000 -a 0.125`
@@ -53,8 +54,6 @@ printdate "Started $APP_BASE_NAME with parameters:"
printscriptparams
printbreak
-registerdisputeagents
-
# Demonstrate how to create a country based, face to face account.
showcreatepaymentacctsteps "Alice" "$ALICE_PORT"
diff --git a/apitest/src/main/java/bisq/apitest/ApiTestMain.java b/apitest/src/main/java/bisq/apitest/ApiTestMain.java
index 6d50d19edd8..8ea7e0511be 100644
--- a/apitest/src/main/java/bisq/apitest/ApiTestMain.java
+++ b/apitest/src/main/java/bisq/apitest/ApiTestMain.java
@@ -48,7 +48,7 @@
*
* All method, scenario and end-to-end tests are found in the test sources folder.
*
- * Requires bitcoind v0.19, v0.20, or v0.21.
+ * Requires bitcoind v0.19 - v22.
*/
@Slf4j
public class ApiTestMain {
diff --git a/apitest/src/main/java/bisq/apitest/linux/AbstractLinuxProcess.java b/apitest/src/main/java/bisq/apitest/linux/AbstractLinuxProcess.java
index 83ae6718ae6..9af3bfce379 100644
--- a/apitest/src/main/java/bisq/apitest/linux/AbstractLinuxProcess.java
+++ b/apitest/src/main/java/bisq/apitest/linux/AbstractLinuxProcess.java
@@ -108,7 +108,7 @@ public void verifyBitcoinPathsExist(boolean verbose) {
File bitcoindExecutable = Paths.get(config.bitcoinPath, "bitcoind").toFile();
if (!bitcoindExecutable.exists() || !bitcoindExecutable.canExecute())
throw new IllegalStateException(format("'%s' cannot be found or executed.%n"
- + "A bitcoin-core v0.19, v0.20, or v0.21 installation is required," +
+ + "A bitcoin-core v0.19 - v22 installation is required," +
" and the 'bitcoinPath' must be configured in 'apitest.properties'",
bitcoindExecutable.getAbsolutePath()));
diff --git a/apitest/src/test/java/bisq/apitest/method/offer/AbstractOfferTest.java b/apitest/src/test/java/bisq/apitest/method/offer/AbstractOfferTest.java
index f5b8904815c..218af0e15e1 100644
--- a/apitest/src/test/java/bisq/apitest/method/offer/AbstractOfferTest.java
+++ b/apitest/src/test/java/bisq/apitest/method/offer/AbstractOfferTest.java
@@ -17,7 +17,6 @@
package bisq.apitest.method.offer;
-import bisq.proto.grpc.BsqSwapOfferInfo;
import bisq.proto.grpc.OfferInfo;
import protobuf.PaymentAccount;
@@ -42,10 +41,12 @@
import static bisq.apitest.config.BisqAppConfig.seednode;
import static bisq.cli.table.builder.TableType.OFFER_TBL;
import static bisq.common.util.MathUtils.exactMultiply;
+import static java.lang.System.out;
import bisq.apitest.method.MethodTest;
+import bisq.cli.CliMain;
import bisq.cli.table.builder.TableBuilder;
@Slf4j
@@ -112,11 +113,6 @@ public static void setUp() {
protected final Function, String> toOffersTable = (offers) ->
new TableBuilder(OFFER_TBL, offers).build().toString();
- // TODO
- protected final Function toBsqSwapOfferTable = (offer) ->
- new TableBuilder(OFFER_TBL, offer).build().toString();
-
-
public static void initSwapPaymentAccounts() {
// A bot may not know what the default 'BSQ Swap' account name is,
// but API test cases do: the value of the i18n property 'BSQ_SWAP'.
@@ -140,4 +136,11 @@ public static void createLegacyBsqPaymentAccounts() {
public static void tearDown() {
tearDownScaffold();
}
+
+ protected static void runCliGetOffer(String offerId) {
+ out.println("Alice's CLI 'getmyoffer' response:");
+ CliMain.main(new String[]{"--password=xyz", "--port=9998", "getmyoffer", "--offer-id=" + offerId});
+ out.println("Bob's CLI 'getoffer' response:");
+ CliMain.main(new String[]{"--password=xyz", "--port=9999", "getoffer", "--offer-id=" + offerId});
+ }
}
diff --git a/apitest/src/test/java/bisq/apitest/method/offer/BsqSwapOfferTest.java b/apitest/src/test/java/bisq/apitest/method/offer/BsqSwapOfferTest.java
index bdb516c5157..2810938f5c3 100644
--- a/apitest/src/test/java/bisq/apitest/method/offer/BsqSwapOfferTest.java
+++ b/apitest/src/test/java/bisq/apitest/method/offer/BsqSwapOfferTest.java
@@ -17,7 +17,7 @@
package bisq.apitest.method.offer;
-import bisq.proto.grpc.BsqSwapOfferInfo;
+import bisq.proto.grpc.OfferInfo;
import lombok.extern.slf4j.Slf4j;
@@ -112,8 +112,7 @@ private void createBsqSwapOffer() {
var bsqSwapOffer = aliceClient.createBsqSwapOffer(BUY.name(),
1_000_000L,
1_000_000L,
- "0.00005",
- alicesBsqSwapAcct.getId());
+ "0.00005");
log.debug("BsqSwap Sell BSQ (Buy BTC) OFFER:\n{}", bsqSwapOffer);
var newOfferId = bsqSwapOffer.getId();
assertNotEquals("", newOfferId);
@@ -121,7 +120,6 @@ private void createBsqSwapOffer() {
assertEquals(5_000, bsqSwapOffer.getPrice());
assertEquals(1_000_000L, bsqSwapOffer.getAmount());
assertEquals(1_000_000L, bsqSwapOffer.getMinAmount());
- // assertEquals(alicesBsqAcct.getId(), atomicOffer.getMakerPaymentAccountId());
assertEquals(BSQ, bsqSwapOffer.getBaseCurrencyCode());
assertEquals(BTC, bsqSwapOffer.getCounterCurrencyCode());
@@ -129,13 +127,13 @@ private void createBsqSwapOffer() {
testGetBsqSwapOffer(bsqSwapOffer);
}
- private void testGetMyBsqSwapOffer(BsqSwapOfferInfo bsqSwapOfferInfo) {
+ private void testGetMyBsqSwapOffer(OfferInfo bsqSwapOffer) {
int numFetchAttempts = 0;
while (true) {
try {
numFetchAttempts++;
- var fetchedBsqSwapOffer = aliceClient.getMyBsqSwapOffer(bsqSwapOfferInfo.getId());
- assertEquals(bsqSwapOfferInfo.getId(), fetchedBsqSwapOffer.getId());
+ var fetchedBsqSwapOffer = aliceClient.getMyOffer(bsqSwapOffer.getId());
+ assertEquals(bsqSwapOffer.getId(), fetchedBsqSwapOffer.getId());
log.debug("Alice found her (my) new bsq swap offer on attempt # {}.", numFetchAttempts);
break;
} catch (Exception ex) {
@@ -149,13 +147,13 @@ private void testGetMyBsqSwapOffer(BsqSwapOfferInfo bsqSwapOfferInfo) {
}
}
- private void testGetBsqSwapOffer(BsqSwapOfferInfo bsqSwapOfferInfo) {
+ private void testGetBsqSwapOffer(OfferInfo bsqSwapOffer) {
int numFetchAttempts = 0;
while (true) {
try {
numFetchAttempts++;
- var fetchedBsqSwapOffer = bobClient.getBsqSwapOffer(bsqSwapOfferInfo.getId());
- assertEquals(bsqSwapOfferInfo.getId(), fetchedBsqSwapOffer.getId());
+ var fetchedBsqSwapOffer = bobClient.getOffer(bsqSwapOffer.getId());
+ assertEquals(bsqSwapOffer.getId(), fetchedBsqSwapOffer.getId());
log.debug("Bob found new available bsq swap offer on attempt # {}.", numFetchAttempts);
break;
} catch (Exception ex) {
diff --git a/apitest/src/test/java/bisq/apitest/method/offer/EditOfferTest.java b/apitest/src/test/java/bisq/apitest/method/offer/EditOfferTest.java
index 59c231d07b7..559f137882a 100644
--- a/apitest/src/test/java/bisq/apitest/method/offer/EditOfferTest.java
+++ b/apitest/src/test/java/bisq/apitest/method/offer/EditOfferTest.java
@@ -38,15 +38,13 @@
import org.junit.jupiter.api.TestMethodOrder;
import static bisq.apitest.config.ApiTestConfig.BSQ;
+import static bisq.apitest.config.ApiTestConfig.BTC;
import static bisq.apitest.config.ApiTestConfig.EUR;
import static bisq.apitest.config.ApiTestConfig.USD;
import static bisq.core.btc.wallet.Restrictions.getDefaultBuyerSecurityDepositAsPercent;
import static bisq.proto.grpc.EditOfferRequest.EditType.*;
import static java.lang.String.format;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.*;
import static protobuf.OfferDirection.BUY;
import static protobuf.OfferDirection.SELL;
@@ -70,22 +68,22 @@ public void testOfferDisableAndEnable() {
paymentAcct.getId(),
0.0,
NO_TRIGGER_PRICE);
- log.debug("ORIGINAL EUR OFFER:\n{}", toOfferTable.apply(originalOffer));
+ log.debug("Original EUR offer:\n{}", toOfferTable.apply(originalOffer));
assertFalse(originalOffer.getIsActivated()); // Not activated until prep is done.
- genBtcBlocksThenWait(1, 2500); // Wait for offer book entry.
+ genBtcBlocksThenWait(1, 2_500); // Wait for offer book entry.
originalOffer = aliceClient.getMyOffer(originalOffer.getId());
assertTrue(originalOffer.getIsActivated());
// Disable offer
aliceClient.editOfferActivationState(originalOffer.getId(), DEACTIVATE_OFFER);
genBtcBlocksThenWait(1, 1500); // Wait for offer book removal.
OfferInfo editedOffer = aliceClient.getMyOffer(originalOffer.getId());
- log.debug("EDITED EUR OFFER:\n{}", toOfferTable.apply(editedOffer));
+ log.debug("Edited EUR offer:\n{}", toOfferTable.apply(editedOffer));
assertFalse(editedOffer.getIsActivated());
// Re-enable offer
aliceClient.editOfferActivationState(editedOffer.getId(), ACTIVATE_OFFER);
genBtcBlocksThenWait(1, 1500); // Wait for offer book re-entry.
editedOffer = aliceClient.getMyOffer(originalOffer.getId());
- log.debug("EDITED EUR OFFER:\n{}", toOfferTable.apply(editedOffer));
+ log.debug("Edited EUR offer:\n{}", toOfferTable.apply(editedOffer));
assertTrue(editedOffer.getIsActivated());
doSanityCheck(originalOffer, editedOffer);
@@ -100,8 +98,8 @@ public void testEditTriggerPrice() {
paymentAcct.getId(),
0.0,
NO_TRIGGER_PRICE);
- log.debug("ORIGINAL EUR OFFER:\n{}", toOfferTable.apply(originalOffer));
- genBtcBlocksThenWait(1, 2500); // Wait for offer book entry.
+ log.debug("Original EUR offer:\n{}", toOfferTable.apply(originalOffer));
+ genBtcBlocksThenWait(1, 2_500); // Wait for offer book entry.
originalOffer = aliceClient.getMyOffer(originalOffer.getId());
assertEquals(0 /*no trigger price*/, originalOffer.getTriggerPrice());
@@ -111,9 +109,9 @@ public void testEditTriggerPrice() {
var newTriggerPriceAsLong = calcPriceAsLong.apply(mktPrice, delta);
aliceClient.editOfferTriggerPrice(originalOffer.getId(), newTriggerPriceAsLong);
- sleep(2500); // Wait for offer book re-entry.
+ sleep(2_500); // Wait for offer book re-entry.
OfferInfo editedOffer = aliceClient.getMyOffer(originalOffer.getId());
- log.debug("EDITED EUR OFFER:\n{}", toOfferTable.apply(editedOffer));
+ log.debug("Edited EUR offer:\n{}", toOfferTable.apply(editedOffer));
assertEquals(newTriggerPriceAsLong, editedOffer.getTriggerPrice());
assertTrue(editedOffer.getUseMarketBasedPrice());
@@ -124,13 +122,13 @@ public void testEditTriggerPrice() {
@Order(3)
public void testSetTriggerPriceToNegativeValueShouldThrowException() {
PaymentAccount paymentAcct = getOrCreatePaymentAccount("FI");
- final OfferInfo originalOffer = createMktPricedOfferForEdit(SELL.name(),
+ var originalOffer = createMktPricedOfferForEdit(SELL.name(),
EUR,
paymentAcct.getId(),
0.0,
NO_TRIGGER_PRICE);
- log.debug("ORIGINAL EUR OFFER:\n{}", toOfferTable.apply(originalOffer));
- genBtcBlocksThenWait(1, 2500); // Wait for offer book entry.
+ log.debug("Original EUR offer:\n{}", toOfferTable.apply(originalOffer));
+ genBtcBlocksThenWait(1, 2_500); // Wait for offer book entry.
// Edit the offer's trigger price, set to -1, check error.
Throwable exception = assertThrows(StatusRuntimeException.class, () ->
aliceClient.editOfferTriggerPrice(originalOffer.getId(), -1L));
@@ -145,19 +143,19 @@ public void testSetTriggerPriceToNegativeValueShouldThrowException() {
public void testEditMktPriceMargin() {
PaymentAccount paymentAcct = getOrCreatePaymentAccount("US");
var originalMktPriceMargin = new BigDecimal("0.1").doubleValue();
- OfferInfo originalOffer = createMktPricedOfferForEdit(SELL.name(),
+ var originalOffer = createMktPricedOfferForEdit(SELL.name(),
USD,
paymentAcct.getId(),
originalMktPriceMargin,
NO_TRIGGER_PRICE);
- log.debug("ORIGINAL USD OFFER:\n{}", toOfferTable.apply(originalOffer));
- genBtcBlocksThenWait(1, 2500); // Wait for offer book entry.
+ log.debug("Original USD offer:\n{}", toOfferTable.apply(originalOffer));
+ genBtcBlocksThenWait(1, 2_500); // Wait for offer book entry.
assertEquals(scaledDownMktPriceMargin.apply(originalMktPriceMargin), originalOffer.getMarketPriceMargin());
// Edit the offer's price margin, nothing else.
var newMktPriceMargin = new BigDecimal("0.5").doubleValue();
aliceClient.editOfferPriceMargin(originalOffer.getId(), newMktPriceMargin);
OfferInfo editedOffer = aliceClient.getMyOffer(originalOffer.getId());
- log.debug("EDITED USD OFFER:\n{}", toOfferTable.apply(editedOffer));
+ log.debug("Edited USD offer:\n{}", toOfferTable.apply(editedOffer));
assertEquals(scaledDownMktPriceMargin.apply(newMktPriceMargin), editedOffer.getMarketPriceMargin());
doSanityCheck(originalOffer, editedOffer);
@@ -169,19 +167,19 @@ public void testEditFixedPrice() {
PaymentAccount paymentAcct = getOrCreatePaymentAccount("RU");
double mktPriceAsDouble = aliceClient.getBtcPrice(RUBLE);
String fixedPriceAsString = calcPriceAsString.apply(mktPriceAsDouble, 200_000.0000);
- OfferInfo originalOffer = createFixedPricedOfferForEdit(BUY.name(),
+ var originalOffer = createFixedPricedOfferForEdit(BUY.name(),
RUBLE,
paymentAcct.getId(),
fixedPriceAsString);
- log.debug("ORIGINAL RUB OFFER:\n{}", toOfferTable.apply(originalOffer));
- genBtcBlocksThenWait(1, 2500); // Wait for offer book entry.
+ log.debug("Original RUB offer:\n{}", toOfferTable.apply(originalOffer));
+ genBtcBlocksThenWait(1, 2_500); // Wait for offer book entry.
// Edit the offer's fixed price, nothing else.
String editedFixedPriceAsString = calcPriceAsString.apply(mktPriceAsDouble, 100_000.0000);
aliceClient.editOfferFixedPrice(originalOffer.getId(), editedFixedPriceAsString);
// Wait for edited offer to be removed from offer-book, edited, and re-published.
- genBtcBlocksThenWait(1, 2500);
+ genBtcBlocksThenWait(1, 2_500);
OfferInfo editedOffer = aliceClient.getMyOffer(originalOffer.getId());
- log.debug("EDITED RUB OFFER:\n{}", toOfferTable.apply(editedOffer));
+ log.debug("Edited RUB offer:\n{}", toOfferTable.apply(editedOffer));
var expectedNewFixedPrice = scaledUpFiatOfferPrice.apply(new BigDecimal(editedFixedPriceAsString));
assertEquals(expectedNewFixedPrice, editedOffer.getPrice());
assertFalse(editedOffer.getUseMarketBasedPrice());
@@ -195,12 +193,12 @@ public void testEditFixedPriceAndDeactivation() {
PaymentAccount paymentAcct = getOrCreatePaymentAccount("RU");
double mktPriceAsDouble = aliceClient.getBtcPrice(RUBLE);
String fixedPriceAsString = calcPriceAsString.apply(mktPriceAsDouble, 200_000.0000);
- OfferInfo originalOffer = createFixedPricedOfferForEdit(BUY.name(),
+ var originalOffer = createFixedPricedOfferForEdit(BUY.name(),
RUBLE,
paymentAcct.getId(),
fixedPriceAsString);
- log.debug("ORIGINAL RUB OFFER:\n{}", toOfferTable.apply(originalOffer));
- genBtcBlocksThenWait(1, 2500); // Wait for offer book entry.
+ log.debug("Original RUB offer:\n{}", toOfferTable.apply(originalOffer));
+ genBtcBlocksThenWait(1, 2_500); // Wait for offer book entry.
// Edit the offer's fixed price and deactivate it.
String editedFixedPriceAsString = calcPriceAsString.apply(mktPriceAsDouble, 100_000.0000);
aliceClient.editOffer(originalOffer.getId(),
@@ -211,9 +209,9 @@ public void testEditFixedPriceAndDeactivation() {
DEACTIVATE_OFFER,
FIXED_PRICE_AND_ACTIVATION_STATE);
// Wait for edited offer to be removed from offer-book, edited, and re-published.
- genBtcBlocksThenWait(1, 2500);
+ genBtcBlocksThenWait(1, 2_500);
OfferInfo editedOffer = aliceClient.getMyOffer(originalOffer.getId());
- log.debug("EDITED RUB OFFER:\n{}", toOfferTable.apply(editedOffer));
+ log.debug("Edited RUB offer:\n{}", toOfferTable.apply(editedOffer));
var expectedNewFixedPrice = scaledUpFiatOfferPrice.apply(new BigDecimal(editedFixedPriceAsString));
assertEquals(expectedNewFixedPrice, editedOffer.getPrice());
assertFalse(editedOffer.getIsActivated());
@@ -232,8 +230,8 @@ public void testEditMktPriceMarginAndDeactivation() {
paymentAcct.getId(),
originalMktPriceMargin,
0);
- log.debug("ORIGINAL USD OFFER:\n{}", toOfferTable.apply(originalOffer));
- genBtcBlocksThenWait(1, 2500); // Wait for offer book entry.
+ log.debug("Original USD offer:\n{}", toOfferTable.apply(originalOffer));
+ genBtcBlocksThenWait(1, 2_500); // Wait for offer book entry.
originalOffer = aliceClient.getMyOffer(originalOffer.getId());
assertEquals(scaledDownMktPriceMargin.apply(originalMktPriceMargin), originalOffer.getMarketPriceMargin());
@@ -247,9 +245,9 @@ public void testEditMktPriceMarginAndDeactivation() {
DEACTIVATE_OFFER,
MKT_PRICE_MARGIN_AND_ACTIVATION_STATE);
// Wait for edited offer to be removed from offer-book, edited, and re-published.
- genBtcBlocksThenWait(1, 2500);
+ genBtcBlocksThenWait(1, 2_500);
OfferInfo editedOffer = aliceClient.getMyOffer(originalOffer.getId());
- log.debug("EDITED USD OFFER:\n{}", toOfferTable.apply(editedOffer));
+ log.debug("Edited USD offer:\n{}", toOfferTable.apply(editedOffer));
assertEquals(scaledDownMktPriceMargin.apply(newMktPriceMargin), editedOffer.getMarketPriceMargin());
assertEquals(0, editedOffer.getTriggerPrice());
assertFalse(editedOffer.getIsActivated());
@@ -261,18 +259,16 @@ public void testEditMktPriceMarginAndDeactivation() {
@Order(8)
public void testEditMktPriceMarginAndTriggerPriceAndDeactivation() {
PaymentAccount paymentAcct = getOrCreatePaymentAccount("US");
-
var originalMktPriceMargin = new BigDecimal("0.0").doubleValue();
var mktPriceAsDouble = aliceClient.getBtcPrice(USD);
var originalTriggerPriceAsLong = calcPriceAsLong.apply(mktPriceAsDouble, -5_000.0000);
-
OfferInfo originalOffer = createMktPricedOfferForEdit(SELL.name(),
USD,
paymentAcct.getId(),
originalMktPriceMargin,
originalTriggerPriceAsLong);
- log.debug("ORIGINAL USD OFFER:\n{}", toOfferTable.apply(originalOffer));
- genBtcBlocksThenWait(1, 2500); // Wait for offer book entry.
+ log.debug("Original USD offer:\n{}", toOfferTable.apply(originalOffer));
+ genBtcBlocksThenWait(1, 2_500); // Wait for offer book entry.
originalOffer = aliceClient.getMyOffer(originalOffer.getId());
assertEquals(scaledDownMktPriceMargin.apply(originalMktPriceMargin), originalOffer.getMarketPriceMargin());
assertEquals(originalTriggerPriceAsLong, originalOffer.getTriggerPrice());
@@ -288,9 +284,9 @@ public void testEditMktPriceMarginAndTriggerPriceAndDeactivation() {
DEACTIVATE_OFFER,
MKT_PRICE_MARGIN_AND_TRIGGER_PRICE_AND_ACTIVATION_STATE);
// Wait for edited offer to be removed from offer-book, edited, and re-published.
- genBtcBlocksThenWait(1, 2500);
+ genBtcBlocksThenWait(1, 2_500);
OfferInfo editedOffer = aliceClient.getMyOffer(originalOffer.getId());
- log.debug("EDITED USD OFFER:\n{}", toOfferTable.apply(editedOffer));
+ log.debug("Edited USD offer:\n{}", toOfferTable.apply(editedOffer));
assertEquals(scaledDownMktPriceMargin.apply(newMktPriceMargin), editedOffer.getMarketPriceMargin());
assertEquals(newTriggerPriceAsLong, editedOffer.getTriggerPrice());
assertFalse(editedOffer.getIsActivated());
@@ -303,13 +299,13 @@ public void testEditMktPriceMarginAndTriggerPriceAndDeactivation() {
public void testEditingFixedPriceInMktPriceMarginBasedOfferShouldThrowException() {
PaymentAccount paymentAcct = getOrCreatePaymentAccount("US");
var originalMktPriceMargin = new BigDecimal("0.0").doubleValue();
- final OfferInfo originalOffer = createMktPricedOfferForEdit(SELL.name(),
+ var originalOffer = createMktPricedOfferForEdit(SELL.name(),
USD,
paymentAcct.getId(),
originalMktPriceMargin,
NO_TRIGGER_PRICE);
- log.debug("ORIGINAL USD OFFER:\n{}", toOfferTable.apply(originalOffer));
- genBtcBlocksThenWait(1, 2500); // Wait for offer book entry.
+ log.debug("Original USD offer:\n{}", toOfferTable.apply(originalOffer));
+ genBtcBlocksThenWait(1, 2_500); // Wait for offer book entry.
// Try to edit both the fixed price and mkt price margin.
var newMktPriceMargin = new BigDecimal("0.25").doubleValue();
var newFixedPrice = "50000.0000";
@@ -335,12 +331,12 @@ public void testEditingTriggerPriceInFixedPriceOfferShouldThrowException() {
PaymentAccount paymentAcct = getOrCreatePaymentAccount("RU");
double mktPriceAsDouble = aliceClient.getBtcPrice(RUBLE);
String fixedPriceAsString = calcPriceAsString.apply(mktPriceAsDouble, 200_000.0000);
- OfferInfo originalOffer = createFixedPricedOfferForEdit(BUY.name(),
+ var originalOffer = createFixedPricedOfferForEdit(BUY.name(),
RUBLE,
paymentAcct.getId(),
fixedPriceAsString);
- log.debug("ORIGINAL RUB OFFER:\n{}", toOfferTable.apply(originalOffer));
- genBtcBlocksThenWait(1, 2500); // Wait for offer book entry.
+ log.debug("Original RUB offer:\n{}", toOfferTable.apply(originalOffer));
+ genBtcBlocksThenWait(1, 2_500); // Wait for offer book entry.
long newTriggerPrice = 1000000L;
Throwable exception = assertThrows(StatusRuntimeException.class, () ->
aliceClient.editOfferTriggerPrice(originalOffer.getId(), newTriggerPrice));
@@ -358,12 +354,12 @@ public void testChangeFixedPriceOfferToPriceMarginBasedOfferWithTriggerPrice() {
PaymentAccount paymentAcct = getOrCreatePaymentAccount("MX");
double mktPriceAsDouble = aliceClient.getBtcPrice("MXN");
String fixedPriceAsString = calcPriceAsString.apply(mktPriceAsDouble, 0.00);
- OfferInfo originalOffer = createFixedPricedOfferForEdit(BUY.name(),
+ var originalOffer = createFixedPricedOfferForEdit(BUY.name(),
"MXN",
paymentAcct.getId(),
fixedPriceAsString);
- log.debug("ORIGINAL MXN OFFER:\n{}", toOfferTable.apply(originalOffer));
- genBtcBlocksThenWait(1, 2500); // Wait for offer book entry.
+ log.debug("Original MXN offer:\n{}", toOfferTable.apply(originalOffer));
+ genBtcBlocksThenWait(1, 2_500); // Wait for offer book entry.
// Change the offer to mkt price based and set a trigger price.
var newMktPriceMargin = new BigDecimal("0.05").doubleValue();
@@ -377,9 +373,9 @@ public void testChangeFixedPriceOfferToPriceMarginBasedOfferWithTriggerPrice() {
ACTIVATE_OFFER,
MKT_PRICE_MARGIN_AND_TRIGGER_PRICE);
// Wait for edited offer to be removed from offer-book, edited, and re-published.
- genBtcBlocksThenWait(1, 2500);
+ genBtcBlocksThenWait(1, 2_500);
OfferInfo editedOffer = aliceClient.getMyOffer(originalOffer.getId());
- log.debug("EDITED MXN OFFER:\n{}", toOfferTable.apply(editedOffer));
+ log.debug("Edited MXN offer:\n{}", toOfferTable.apply(editedOffer));
assertTrue(editedOffer.getUseMarketBasedPrice());
assertEquals(scaledDownMktPriceMargin.apply(newMktPriceMargin), editedOffer.getMarketPriceMargin());
assertEquals(newTriggerPriceAsLong, editedOffer.getTriggerPrice());
@@ -396,13 +392,13 @@ public void testChangePriceMarginBasedOfferToFixedPriceOfferAndDeactivateIt() {
var originalMktPriceMargin = new BigDecimal("0.25").doubleValue();
var delta = 1_000.0000; // trigger price on sell offer is 1K below mkt price
var originalTriggerPriceAsLong = calcPriceAsLong.apply(mktPriceAsDouble, delta);
- final OfferInfo originalOffer = createMktPricedOfferForEdit(SELL.name(),
+ var originalOffer = createMktPricedOfferForEdit(SELL.name(),
"GBP",
paymentAcct.getId(),
originalMktPriceMargin,
originalTriggerPriceAsLong);
- log.debug("ORIGINAL GBP OFFER:\n{}", toOfferTable.apply(originalOffer));
- genBtcBlocksThenWait(1, 2500); // Wait for offer book entry.
+ log.debug("Original GBP offer:\n{}", toOfferTable.apply(originalOffer));
+ genBtcBlocksThenWait(1, 2_500); // Wait for offer book entry.
String fixedPriceAsString = calcPriceAsString.apply(mktPriceAsDouble, 0.00);
aliceClient.editOffer(originalOffer.getId(),
@@ -413,9 +409,9 @@ public void testChangePriceMarginBasedOfferToFixedPriceOfferAndDeactivateIt() {
DEACTIVATE_OFFER,
FIXED_PRICE_AND_ACTIVATION_STATE);
// Wait for edited offer to be removed from offer-book, edited, and re-published.
- genBtcBlocksThenWait(1, 2500);
+ genBtcBlocksThenWait(1, 2_500);
OfferInfo editedOffer = aliceClient.getMyOffer(originalOffer.getId());
- log.debug("EDITED GBP OFFER:\n{}", toOfferTable.apply(editedOffer));
+ log.debug("Edited GBP offer:\n{}", toOfferTable.apply(editedOffer));
assertEquals(scaledUpFiatOfferPrice.apply(new BigDecimal(fixedPriceAsString)), editedOffer.getPrice());
assertFalse(editedOffer.getUseMarketBasedPrice());
assertEquals(0.00, editedOffer.getMarketPriceMargin());
@@ -426,7 +422,7 @@ public void testChangePriceMarginBasedOfferToFixedPriceOfferAndDeactivateIt() {
@Test
@Order(13)
public void testChangeFixedPricedBsqOfferToPriceMarginBasedOfferShouldThrowException() {
- OfferInfo originalOffer = aliceClient.createFixedPricedOffer(BUY.name(),
+ var originalOffer = aliceClient.createFixedPricedOffer(BUY.name(),
BSQ,
100_000_000L,
100_000_000L,
@@ -434,8 +430,8 @@ public void testChangeFixedPricedBsqOfferToPriceMarginBasedOfferShouldThrowExcep
getDefaultBuyerSecurityDepositAsPercent(),
alicesLegacyBsqAcct.getId(),
BSQ);
- log.debug("ORIGINAL BSQ OFFER:\n{}", toOfferTable.apply(originalOffer));
- genBtcBlocksThenWait(1, 2500); // Wait for offer book entry.
+ log.debug("Original BSQ offer:\n{}", toOfferTable.apply(originalOffer));
+ genBtcBlocksThenWait(1, 2_500); // Wait for offer book entry.
Throwable exception = assertThrows(StatusRuntimeException.class, () ->
aliceClient.editOffer(originalOffer.getId(),
"0.00",
@@ -453,7 +449,7 @@ public void testChangeFixedPricedBsqOfferToPriceMarginBasedOfferShouldThrowExcep
@Test
@Order(14)
public void testEditTriggerPriceOnFixedPriceBsqOfferShouldThrowException() {
- OfferInfo originalOffer = aliceClient.createFixedPricedOffer(BUY.name(),
+ var originalOffer = aliceClient.createFixedPricedOffer(BUY.name(),
BSQ,
100_000_000L,
100_000_000L,
@@ -461,8 +457,8 @@ public void testEditTriggerPriceOnFixedPriceBsqOfferShouldThrowException() {
getDefaultBuyerSecurityDepositAsPercent(),
alicesLegacyBsqAcct.getId(),
BSQ);
- log.debug("ORIGINAL BSQ OFFER:\n{}", toOfferTable.apply(originalOffer));
- genBtcBlocksThenWait(1, 2500); // Wait for offer book entry.
+ log.debug("Original BSQ offer:\n{}", toOfferTable.apply(originalOffer));
+ genBtcBlocksThenWait(1, 2_500); // Wait for offer book entry.
var newTriggerPriceAsLong = calcPriceAsLong.apply(0.00005, 0.00);
Throwable exception = assertThrows(StatusRuntimeException.class, () ->
aliceClient.editOffer(originalOffer.getId(),
@@ -482,7 +478,7 @@ public void testEditTriggerPriceOnFixedPriceBsqOfferShouldThrowException() {
@Order(15)
public void testEditFixedPriceOnBsqOffer() {
String fixedPriceAsString = "0.00005"; // FIXED PRICE IN BTC (satoshis) FOR 1 BSQ
- final OfferInfo originalOffer = aliceClient.createFixedPricedOffer(BUY.name(),
+ var originalOffer = aliceClient.createFixedPricedOffer(BUY.name(),
BSQ,
100_000_000L,
100_000_000L,
@@ -490,8 +486,8 @@ public void testEditFixedPriceOnBsqOffer() {
getDefaultBuyerSecurityDepositAsPercent(),
alicesLegacyBsqAcct.getId(),
BSQ);
- log.debug("ORIGINAL BSQ OFFER:\n{}", toOfferTable.apply(originalOffer));
- genBtcBlocksThenWait(1, 2500); // Wait for offer book entry.
+ log.debug("Original BSQ offer:\n{}", toOfferTable.apply(originalOffer));
+ genBtcBlocksThenWait(1, 2_500); // Wait for offer book entry.
String newFixedPriceAsString = "0.00003111";
aliceClient.editOffer(originalOffer.getId(),
newFixedPriceAsString,
@@ -501,9 +497,9 @@ public void testEditFixedPriceOnBsqOffer() {
ACTIVATE_OFFER,
FIXED_PRICE_ONLY);
// Wait for edited offer to be edited and removed from offer-book.
- genBtcBlocksThenWait(1, 2500);
+ genBtcBlocksThenWait(1, 2_500);
OfferInfo editedOffer = aliceClient.getMyOffer(originalOffer.getId());
- log.debug("EDITED BSQ OFFER:\n{}", toOfferTable.apply(editedOffer));
+ log.debug("Edited BSQ offer:\n{}", toOfferTable.apply(editedOffer));
assertEquals(scaledUpAltcoinOfferPrice.apply(newFixedPriceAsString), editedOffer.getPrice());
assertTrue(editedOffer.getIsActivated());
assertFalse(editedOffer.getUseMarketBasedPrice());
@@ -515,7 +511,7 @@ public void testEditFixedPriceOnBsqOffer() {
@Order(16)
public void testDisableBsqOffer() {
String fixedPriceAsString = "0.00005"; // FIXED PRICE IN BTC (satoshis) FOR 1 BSQ
- final OfferInfo originalOffer = aliceClient.createFixedPricedOffer(BUY.name(),
+ var originalOffer = aliceClient.createFixedPricedOffer(BUY.name(),
BSQ,
100_000_000L,
100_000_000L,
@@ -523,8 +519,8 @@ public void testDisableBsqOffer() {
getDefaultBuyerSecurityDepositAsPercent(),
alicesLegacyBsqAcct.getId(),
BSQ);
- log.debug("ORIGINAL BSQ OFFER:\n{}", toOfferTable.apply(originalOffer));
- genBtcBlocksThenWait(1, 2500); // Wait for offer book entry.
+ log.debug("Original BSQ offer:\n{}", toOfferTable.apply(originalOffer));
+ genBtcBlocksThenWait(1, 2_500); // Wait for offer book entry.
aliceClient.editOffer(originalOffer.getId(),
fixedPriceAsString,
false,
@@ -533,9 +529,9 @@ public void testDisableBsqOffer() {
DEACTIVATE_OFFER,
ACTIVATION_STATE_ONLY);
// Wait for edited offer to be removed from offer-book.
- genBtcBlocksThenWait(1, 2500);
+ genBtcBlocksThenWait(1, 2_500);
OfferInfo editedOffer = aliceClient.getMyOffer(originalOffer.getId());
- log.debug("EDITED BSQ OFFER:\n{}", toOfferTable.apply(editedOffer));
+ log.debug("Edited BSQ offer:\n{}", toOfferTable.apply(editedOffer));
assertFalse(editedOffer.getIsActivated());
assertEquals(scaledUpAltcoinOfferPrice.apply(fixedPriceAsString), editedOffer.getPrice());
assertFalse(editedOffer.getUseMarketBasedPrice());
@@ -547,7 +543,7 @@ public void testDisableBsqOffer() {
@Order(17)
public void testEditFixedPriceAndDisableBsqOffer() {
String fixedPriceAsString = "0.00005"; // FIXED PRICE IN BTC (satoshis) FOR 1 BSQ
- final OfferInfo originalOffer = aliceClient.createFixedPricedOffer(BUY.name(),
+ var originalOffer = aliceClient.createFixedPricedOffer(BUY.name(),
BSQ,
100_000_000L,
100_000_000L,
@@ -555,8 +551,8 @@ public void testEditFixedPriceAndDisableBsqOffer() {
getDefaultBuyerSecurityDepositAsPercent(),
alicesLegacyBsqAcct.getId(),
BSQ);
- log.debug("ORIGINAL BSQ OFFER:\n{}", toOfferTable.apply(originalOffer));
- genBtcBlocksThenWait(1, 2500); // Wait for offer book entry.
+ log.debug("Original BSQ offer:\n{}", toOfferTable.apply(originalOffer));
+ genBtcBlocksThenWait(1, 2_500); // Wait for offer book entry.
String newFixedPriceAsString = "0.000045";
aliceClient.editOffer(originalOffer.getId(),
newFixedPriceAsString,
@@ -566,9 +562,9 @@ public void testEditFixedPriceAndDisableBsqOffer() {
DEACTIVATE_OFFER,
FIXED_PRICE_AND_ACTIVATION_STATE);
// Wait for edited offer to be edited and removed from offer-book.
- genBtcBlocksThenWait(1, 2500);
+ genBtcBlocksThenWait(1, 2_500);
OfferInfo editedOffer = aliceClient.getMyOffer(originalOffer.getId());
- log.debug("EDITED BSQ OFFER:\n{}", toOfferTable.apply(editedOffer));
+ log.debug("Edited BSQ offer:\n{}", toOfferTable.apply(editedOffer));
assertFalse(editedOffer.getIsActivated());
assertEquals(scaledUpAltcoinOfferPrice.apply(newFixedPriceAsString), editedOffer.getPrice());
assertFalse(editedOffer.getUseMarketBasedPrice());
@@ -576,6 +572,39 @@ public void testEditFixedPriceAndDisableBsqOffer() {
assertEquals(0, editedOffer.getTriggerPrice());
}
+ @Test
+ @Order(18)
+ public void testEditBsqSwapOfferShouldThrowException() {
+ var originalOffer = aliceClient.createBsqSwapOffer(SELL.name(),
+ 1_250_000L,
+ 750_000L,
+ "0.00005");
+ log.debug("BsqSwap Buy BSQ (Buy BTC) offer:\n{}", originalOffer);
+ var newOfferId = originalOffer.getId();
+ assertNotEquals("", newOfferId);
+ assertEquals(SELL.name(), originalOffer.getDirection());
+ assertEquals(5_000, originalOffer.getPrice());
+ assertEquals(1_250_000L, originalOffer.getAmount());
+ assertEquals(750_000L, originalOffer.getMinAmount());
+ assertEquals(BSQ, originalOffer.getBaseCurrencyCode());
+ assertEquals(BTC, originalOffer.getCounterCurrencyCode());
+
+ log.debug("Original BsqSwap offer:\n{}", toOfferTable.apply(originalOffer));
+ genBtcBlocksThenWait(1, 2_500); // Wait for offer book entry.
+ var newFixedPrice = "0.000055";
+ Throwable exception = assertThrows(StatusRuntimeException.class, () ->
+ aliceClient.editOffer(originalOffer.getId(),
+ newFixedPrice,
+ false,
+ 0.0,
+ 0,
+ ACTIVATE_OFFER,
+ TRIGGER_PRICE_ONLY));
+ String expectedExceptionMessage = format("UNKNOWN: cannot edit bsq swap offer with id '%s'",
+ originalOffer.getId());
+ assertEquals(expectedExceptionMessage, exception.getMessage());
+ }
+
private OfferInfo createMktPricedOfferForEdit(String direction,
String currencyCode,
String paymentAccountId,
diff --git a/apitest/src/test/java/bisq/apitest/method/trade/AbstractTradeTest.java b/apitest/src/test/java/bisq/apitest/method/trade/AbstractTradeTest.java
index ba59c1a98f5..84f4f9bac21 100644
--- a/apitest/src/test/java/bisq/apitest/method/trade/AbstractTradeTest.java
+++ b/apitest/src/test/java/bisq/apitest/method/trade/AbstractTradeTest.java
@@ -21,11 +21,13 @@
import static bisq.core.trade.model.bisq_v1.Trade.State.DEPOSIT_CONFIRMED_IN_BLOCK_CHAIN;
import static bisq.core.trade.model.bisq_v1.Trade.State.SELLER_RECEIVED_FIAT_PAYMENT_INITIATED_MSG;
import static java.lang.String.format;
+import static java.lang.System.out;
import static org.junit.jupiter.api.Assertions.*;
import bisq.apitest.method.offer.AbstractOfferTest;
+import bisq.cli.CliMain;
import bisq.cli.GrpcClient;
import bisq.cli.table.builder.TableBuilder;
@@ -37,7 +39,9 @@ public class AbstractTradeTest extends AbstractOfferTest {
protected static String tradeId;
protected final Supplier maxTradeStateAndPhaseChecks = () -> isLongRunningTest ? 10 : 2;
- private final Function toUserName = (client) -> client.equals(aliceClient) ? "Alice" : "Bob";
+ protected final Function toTradeDetailTable = (trade) ->
+ new TableBuilder(TRADE_DETAIL_TBL, trade).build().toString();
+ protected final Function toUserName = (client) -> client.equals(aliceClient) ? "Alice" : "Bob";
@BeforeAll
public static void initStaticFixtures() {
@@ -241,4 +245,11 @@ protected final void logTrade(Logger log,
new TableBuilder(TRADE_DETAIL_TBL, trade).build()));
}
}
+
+ protected static void runCliGetTrade(String tradeId) {
+ out.println("Alice's CLI 'gettrade' response:");
+ CliMain.main(new String[]{"--password=xyz", "--port=9998", "gettrade", "--trade-id=" + tradeId});
+ out.println("Bob's CLI 'gettrade' response:");
+ CliMain.main(new String[]{"--password=xyz", "--port=9999", "gettrade", "--trade-id=" + tradeId});
+ }
}
diff --git a/apitest/src/test/java/bisq/apitest/method/trade/BsqSwapTradeTest.java b/apitest/src/test/java/bisq/apitest/method/trade/BsqSwapTradeTest.java
index 73261907db2..8938231c74a 100644
--- a/apitest/src/test/java/bisq/apitest/method/trade/BsqSwapTradeTest.java
+++ b/apitest/src/test/java/bisq/apitest/method/trade/BsqSwapTradeTest.java
@@ -17,8 +17,8 @@
package bisq.apitest.method.trade;
-import bisq.proto.grpc.BsqSwapOfferInfo;
-import bisq.proto.grpc.BsqSwapTradeInfo;
+import bisq.proto.grpc.OfferInfo;
+import bisq.proto.grpc.TradeInfo;
import java.util.ArrayList;
import java.util.List;
@@ -36,9 +36,11 @@
import static bisq.apitest.config.ApiTestConfig.BSQ;
import static bisq.apitest.config.ApiTestConfig.BTC;
+import static bisq.proto.grpc.GetOfferCategoryReply.OfferCategory.BSQ_SWAP;
import static java.lang.String.format;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static protobuf.BsqSwapTrade.State.COMPLETED;
import static protobuf.BsqSwapTrade.State.PREPARATION;
@@ -47,13 +49,12 @@
import bisq.apitest.method.offer.AbstractOfferTest;
+import bisq.cli.GrpcClient;
@Disabled
@Slf4j
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
-public class BsqSwapTradeTest extends AbstractOfferTest {
-
- private static final String BISQ_FEE_CURRENCY_CODE = BSQ;
+public class BsqSwapTradeTest extends AbstractTradeTest {
// Long-running swap trade tests might want to check node logs for exceptions.
@Setter
@@ -66,7 +67,7 @@ public static void setUp() {
@BeforeEach
public void generateBtcBlock() {
- genBtcBlocksThenWait(1, 2000);
+ genBtcBlocksThenWait(1, 2_000);
}
@Test
@@ -81,54 +82,91 @@ public void testGetBalancesBeforeTrade() {
@Test
@Order(2)
public void testAliceCreateBsqSwapBuyOffer() {
- var bsqSwapOffer = aliceClient.createBsqSwapOffer(BUY.name(),
- 1_000_000L,
+ var mySwapOffer = aliceClient.createBsqSwapOffer(BUY.name(),
+ 1_000_000L, // 0.01 BTC
1_000_000L,
- "0.00005",
- alicesBsqSwapAcct.getId());
- log.debug("BsqSwap Sell BSQ (Buy BTC) OFFER:\n{}", bsqSwapOffer);
- var newOfferId = bsqSwapOffer.getId();
+ "0.00005");
+ log.debug("Pending BsqSwap Sell BSQ (Buy BTC) OFFER:\n{}", toOfferTable.apply(mySwapOffer));
+ var newOfferId = mySwapOffer.getId();
assertNotEquals("", newOfferId);
- assertEquals(BUY.name(), bsqSwapOffer.getDirection());
- assertEquals(5_000, bsqSwapOffer.getPrice());
- assertEquals(1_000_000L, bsqSwapOffer.getAmount());
- assertEquals(1_000_000L, bsqSwapOffer.getMinAmount());
- // assertEquals(alicesBsqAcct.getId(), atomicOffer.getMakerPaymentAccountId());
- assertEquals(BSQ, bsqSwapOffer.getBaseCurrencyCode());
- assertEquals(BTC, bsqSwapOffer.getCounterCurrencyCode());
+ assertEquals(BUY.name(), mySwapOffer.getDirection());
+ assertEquals(5_000, mySwapOffer.getPrice());
+ assertEquals(1_000_000L, mySwapOffer.getAmount());
+ assertEquals(1_000_000L, mySwapOffer.getMinAmount());
+ assertEquals(BSQ, mySwapOffer.getBaseCurrencyCode());
+ assertEquals(BTC, mySwapOffer.getCounterCurrencyCode());
+
+ genBtcBlocksThenWait(1, 2_500);
+
+ mySwapOffer = aliceClient.getMyOffer(newOfferId);
+ log.debug("My fetched BsqSwap Sell BSQ (Buy BTC) OFFER:\n{}", toOfferTable.apply(mySwapOffer));
+ assertNotEquals(0, mySwapOffer.getMakerFee());
+
+ runCliGetOffer(newOfferId);
}
@Test
@Order(3)
public void testBobTakesBsqSwapOffer() {
- var bsqSwapOffer = getAvailableBsqSwapOffer();
- var bsqSwapTradeInfo = bobClient.takeBsqSwapOffer(bsqSwapOffer.getId(),
- bobsBsqSwapAcct.getId(),
- BISQ_FEE_CURRENCY_CODE);
- log.debug("Trade at t1: {}", bsqSwapTradeInfo);
- assertEquals(PREPARATION.name(), bsqSwapTradeInfo.getState());
+ var availableSwapOffer = getAvailableBsqSwapOffer(bobClient);
+
+ // Before sending a TakeOfferRequest, the CLI needs to know what kind of Offer
+ // it is taking (v1 or BsqSwap). Only BSQ swap offers can be taken with a
+ // single offerId parameter. Taking v1 offers requires an additional
+ // paymentAccountId param. The test case knows what kind of offer is being taken,
+ // but we test the gRPC GetOfferCategory service here.
+ var availableOfferCategory = bobClient.getAvailableOfferCategory(availableSwapOffer.getId());
+ assertTrue(availableOfferCategory.equals(BSQ_SWAP));
+
+ sleep(30_000);
+
+ var swapTrade = bobClient.takeBsqSwapOffer(availableSwapOffer.getId());
+ tradeId = swapTrade.getTradeId(); // Cache the tradeId for following test case(s).
+ log.debug("BsqSwap Trade at PREPARATION:\n{}", toTradeDetailTable.apply(swapTrade));
+ assertEquals(PREPARATION.name(), swapTrade.getState());
genBtcBlocksThenWait(1, 3_000);
- bsqSwapTradeInfo = getBsqSwapTrade(bsqSwapTradeInfo.getTradeId());
- log.debug("Trade at t2: {}", bsqSwapTradeInfo);
- assertEquals(COMPLETED.name(), bsqSwapTradeInfo.getState());
+ swapTrade = getBsqSwapTrade(bobClient, tradeId);
+ log.debug("BsqSwap Trade at COMPLETION:\n{}", toTradeDetailTable.apply(swapTrade));
+ assertEquals(COMPLETED.name(), swapTrade.getState());
+
+ runCliGetTrade(tradeId);
}
@Test
@Order(4)
+ public void testCompletedSwapTxConfirmations() {
+ sleep(2_000); // Wait for TX confirmation to happen on node.
+
+ var alicesTrade = getBsqSwapTrade(aliceClient, tradeId);
+ log.debug("Alice's BsqSwap Trade at COMPLETION:\n{}", toTradeDetailTable.apply(alicesTrade));
+ assertEquals(1, alicesTrade.getBsqSwapTradeInfo().getNumConfirmations());
+
+ var bobsTrade = getBsqSwapTrade(bobClient, tradeId);
+ log.debug("Bob's BsqSwap Trade at COMPLETION:\n{}", toTradeDetailTable.apply(bobsTrade));
+ assertEquals(1, bobsTrade.getBsqSwapTradeInfo().getNumConfirmations());
+
+ genBtcBlocksThenWait(1, 2_000);
+
+ bobsTrade = getBsqSwapTrade(bobClient, tradeId);
+ log.debug("Bob's BsqSwap Trade at COMPLETION:\n{}", toTradeDetailTable.apply(bobsTrade));
+ assertEquals(2, bobsTrade.getBsqSwapTradeInfo().getNumConfirmations());
+ }
+
+ @Test
+ @Order(5)
public void testGetBalancesAfterTrade() {
- sleep(2_500); // Give wallet time to finish processing TX.
var alicesBalances = aliceClient.getBalances();
log.debug("Alice's After Trade Balance:\n{}", formatBalancesTbls(alicesBalances));
var bobsBalances = bobClient.getBalances();
log.debug("Bob's After Trade Balance:\n{}", formatBalancesTbls(bobsBalances));
}
- private BsqSwapOfferInfo getAvailableBsqSwapOffer() {
- List bsqSwapOffers = new ArrayList<>();
+ private OfferInfo getAvailableBsqSwapOffer(GrpcClient client) {
+ List bsqSwapOffers = new ArrayList<>();
int numFetchAttempts = 0;
while (bsqSwapOffers.size() == 0) {
- bsqSwapOffers.addAll(bobClient.getBsqSwapOffers(BUY.name(), BSQ));
+ bsqSwapOffers.addAll(client.getBsqSwapOffers(BUY.name()));
numFetchAttempts++;
if (bsqSwapOffers.size() == 0) {
log.warn("No available bsq swap offers found after {} fetch attempts.", numFetchAttempts);
@@ -138,7 +176,7 @@ private BsqSwapOfferInfo getAvailableBsqSwapOffer() {
}
fail(format("Bob gave up on fetching available bsq swap offers after %d attempts.", numFetchAttempts));
}
- sleep(1000);
+ sleep(1_000);
} else {
assertEquals(1, bsqSwapOffers.size());
log.debug("Bob found new available bsq swap offer on attempt # {}.", numFetchAttempts);
@@ -150,12 +188,12 @@ private BsqSwapOfferInfo getAvailableBsqSwapOffer() {
return bsqSwapOffer;
}
- private BsqSwapTradeInfo getBsqSwapTrade(String tradeId) {
+ private TradeInfo getBsqSwapTrade(GrpcClient client, String tradeId) {
int numFetchAttempts = 0;
while (true) {
try {
numFetchAttempts++;
- return bobClient.getBsqSwapTrade(tradeId);
+ return client.getTrade(tradeId);
} catch (Exception ex) {
log.warn(ex.getMessage());
if (numFetchAttempts > 9) {
@@ -164,7 +202,7 @@ private BsqSwapTradeInfo getBsqSwapTrade(String tradeId) {
}
fail(format("Could not find new bsq swap trade after %d attempts.", numFetchAttempts));
} else {
- sleep(1000);
+ sleep(1_000);
}
}
}
diff --git a/apitest/src/test/java/bisq/apitest/scenario/TradeTest.java b/apitest/src/test/java/bisq/apitest/scenario/TradeTest.java
index 63612712514..c4e03ffa2f2 100644
--- a/apitest/src/test/java/bisq/apitest/scenario/TradeTest.java
+++ b/apitest/src/test/java/bisq/apitest/scenario/TradeTest.java
@@ -101,7 +101,9 @@ public void testTakeSellBSQOffer(final TestInfo testInfo) {
@Order(6)
public void testBsqSwapTradeTest(final TestInfo testInfo) {
BsqSwapTradeTest test = new BsqSwapTradeTest();
+ test.testGetBalancesBeforeTrade();
test.testAliceCreateBsqSwapBuyOffer();
test.testBobTakesBsqSwapOffer();
+ test.testGetBalancesAfterTrade();
}
}
diff --git a/cli/src/main/java/bisq/cli/CliMain.java b/cli/src/main/java/bisq/cli/CliMain.java
index bc84aed69f4..5689fbdad0a 100644
--- a/cli/src/main/java/bisq/cli/CliMain.java
+++ b/cli/src/main/java/bisq/cli/CliMain.java
@@ -18,6 +18,7 @@
package bisq.cli;
import bisq.proto.grpc.OfferInfo;
+import bisq.proto.grpc.TradeInfo;
import io.grpc.StatusRuntimeException;
@@ -45,6 +46,7 @@
import static bisq.cli.Method.*;
import static bisq.cli.opts.OptLabel.*;
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.System.err;
import static java.lang.System.exit;
@@ -62,11 +64,11 @@
import bisq.cli.opts.GetAddressBalanceOptionParser;
import bisq.cli.opts.GetBTCMarketPriceOptionParser;
import bisq.cli.opts.GetBalanceOptionParser;
-import bisq.cli.opts.GetOfferOptionParser;
import bisq.cli.opts.GetOffersOptionParser;
import bisq.cli.opts.GetPaymentAcctFormOptionParser;
import bisq.cli.opts.GetTradeOptionParser;
import bisq.cli.opts.GetTransactionOptionParser;
+import bisq.cli.opts.OfferIdOptionParser;
import bisq.cli.opts.RegisterDisputeAgentOptionParser;
import bisq.cli.opts.RemoveWalletPasswordOptionParser;
import bisq.cli.opts.SendBsqOptionParser;
@@ -332,6 +334,7 @@ public static void run(String[] args) {
out.println(client.getMethodHelp(method));
return;
}
+ var isSwap = opts.getIsSwap();
var paymentAcctId = opts.getPaymentAccountId();
var direction = opts.getDirection();
var currencyCode = opts.getCurrencyCode();
@@ -340,30 +343,45 @@ public static void run(String[] args) {
var useMarketBasedPrice = opts.isUsingMktPriceMargin();
var fixedPrice = opts.getFixedPrice();
var marketPriceMargin = opts.getMktPriceMarginAsBigDecimal();
- var securityDeposit = toSecurityDepositAsPct(opts.getSecurityDeposit());
+ var securityDeposit = isSwap ? 0.00 : toSecurityDepositAsPct(opts.getSecurityDeposit());
var makerFeeCurrencyCode = opts.getMakerFeeCurrencyCode();
var triggerPrice = 0; // Cannot be defined until offer is in book.
- var offer = client.createOffer(direction,
- currencyCode,
- amount,
- minAmount,
- useMarketBasedPrice,
- fixedPrice,
- marketPriceMargin.doubleValue(),
- securityDeposit,
- paymentAcctId,
- makerFeeCurrencyCode,
- triggerPrice);
+ OfferInfo offer;
+ if (isSwap) {
+ offer = client.createBsqSwapOffer(direction,
+ amount,
+ minAmount,
+ fixedPrice);
+ } else {
+ offer = client.createOffer(direction,
+ currencyCode,
+ amount,
+ minAmount,
+ useMarketBasedPrice,
+ fixedPrice,
+ marketPriceMargin.doubleValue(),
+ securityDeposit,
+ paymentAcctId,
+ makerFeeCurrencyCode,
+ triggerPrice);
+ }
new TableBuilder(OFFER_TBL, offer).build().print(out);
return;
}
case editoffer: {
- var opts = new EditOfferOptionParser(args).parse();
- if (opts.isForHelp()) {
+ var offerIdOpt = new OfferIdOptionParser(args, true).parse();
+ if (offerIdOpt.isForHelp()) {
out.println(client.getMethodHelp(method));
return;
}
- var offerId = opts.getOfferId();
+ // What kind of offer is being edited? BSQ swaps cannot be edited.
+ var offerId = offerIdOpt.getOfferId();
+ var offerCategory = client.getMyOfferCategory(offerId);
+ if (offerCategory.equals(BSQ_SWAP))
+ throw new IllegalStateException("bsq swap offers cannot be edited,"
+ + " but you may cancel them without forfeiting any funds");
+
+ var opts = new EditOfferOptionParser(args).parse();
var fixedPrice = opts.getFixedPrice();
var isUsingMktPriceMargin = opts.isUsingMktPriceMargin();
var marketPriceMargin = opts.getMktPriceMarginAsBigDecimal();
@@ -392,7 +410,7 @@ public static void run(String[] args) {
return;
}
case getoffer: {
- var opts = new GetOfferOptionParser(args).parse();
+ var opts = new OfferIdOptionParser(args).parse();
if (opts.isForHelp()) {
out.println(client.getMethodHelp(method));
return;
@@ -403,7 +421,7 @@ public static void run(String[] args) {
return;
}
case getmyoffer: {
- var opts = new GetOfferOptionParser(args).parse();
+ var opts = new OfferIdOptionParser(args).parse();
if (opts.isForHelp()) {
out.println(client.getMethodHelp(method));
return;
@@ -446,15 +464,25 @@ public static void run(String[] args) {
return;
}
case takeoffer: {
- var opts = new TakeOfferOptionParser(args).parse();
- if (opts.isForHelp()) {
+ var offerIdOpt = new OfferIdOptionParser(args, true).parse();
+ if (offerIdOpt.isForHelp()) {
out.println(client.getMethodHelp(method));
return;
}
- var offerId = opts.getOfferId();
- var paymentAccountId = opts.getPaymentAccountId();
- var takerFeeCurrencyCode = opts.getTakerFeeCurrencyCode();
- var trade = client.takeOffer(offerId, paymentAccountId, takerFeeCurrencyCode);
+ var offerId = offerIdOpt.getOfferId();
+ TradeInfo trade;
+ // We only send an 'offer-id' param when taking a BsqSwapOffer.
+ // 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());
return;
}
@@ -801,10 +829,11 @@ private static void printHelp(OptionParser parser, @SuppressWarnings("SameParame
stream.format(rowFormat, "", "--currency-code= \\", "");
stream.format(rowFormat, "", "--amount= \\", "");
stream.format(rowFormat, "", "[--min-amount=] \\", "");
- stream.format(rowFormat, "", "--fixed-price= | --market-price=margin= \\", "");
+ stream.format(rowFormat, "", "--fixed-price= | --market-price-margin= \\", "");
stream.format(rowFormat, "", "--security-deposit= \\", "");
stream.format(rowFormat, "", "[--fee-currency=]", "");
stream.format(rowFormat, "", "[--trigger-price=]", "");
+ stream.format(rowFormat, "", "[--swap=]", "");
stream.println();
stream.format(rowFormat, editoffer.name(), "--offer-id= \\", "Edit offer with id");
stream.format(rowFormat, "", "[--fixed-price=] \\", "");
@@ -825,7 +854,7 @@ private static void printHelp(OptionParser parser, @SuppressWarnings("SameParame
stream.format(rowFormat, "", "--currency-code=", "");
stream.println();
stream.format(rowFormat, takeoffer.name(), "--offer-id= \\", "Take offer with id");
- stream.format(rowFormat, "", "--payment-account=", "");
+ stream.format(rowFormat, "", "[--payment-account=]", "");
stream.format(rowFormat, "", "[--fee-currency=]", "");
stream.println();
stream.format(rowFormat, gettrade.name(), "--trade-id= \\", "Get trade summary or full contract");
diff --git a/cli/src/main/java/bisq/cli/GrpcClient.java b/cli/src/main/java/bisq/cli/GrpcClient.java
index dcdaddc5508..6d73bc4ab51 100644
--- a/cli/src/main/java/bisq/cli/GrpcClient.java
+++ b/cli/src/main/java/bisq/cli/GrpcClient.java
@@ -20,17 +20,12 @@
import bisq.proto.grpc.AddressBalanceInfo;
import bisq.proto.grpc.BalancesInfo;
import bisq.proto.grpc.BsqBalanceInfo;
-import bisq.proto.grpc.BsqSwapOfferInfo;
-import bisq.proto.grpc.BsqSwapTradeInfo;
import bisq.proto.grpc.BtcBalanceInfo;
-import bisq.proto.grpc.CreateBsqSwapOfferRequest;
import bisq.proto.grpc.GetMethodHelpRequest;
import bisq.proto.grpc.GetVersionRequest;
import bisq.proto.grpc.OfferInfo;
import bisq.proto.grpc.RegisterDisputeAgentRequest;
import bisq.proto.grpc.StopRequest;
-import bisq.proto.grpc.TakeBsqSwapOfferReply;
-import bisq.proto.grpc.TakeBsqSwapOfferRequest;
import bisq.proto.grpc.TakeOfferReply;
import bisq.proto.grpc.TradeInfo;
import bisq.proto.grpc.TxFeeRateInfo;
@@ -44,6 +39,7 @@
import lombok.extern.slf4j.Slf4j;
import static bisq.proto.grpc.EditOfferRequest.EditType;
+import static bisq.proto.grpc.GetOfferCategoryReply.OfferCategory;
@@ -142,19 +138,22 @@ public TxInfo getTransaction(String txId) {
return walletsServiceRequest.getTransaction(txId);
}
- public BsqSwapOfferInfo createBsqSwapOffer(String direction,
- long amount,
- long minAmount,
- String fixedPrice,
- String paymentAcctId) {
- var request = CreateBsqSwapOfferRequest.newBuilder()
- .setDirection(direction)
- .setAmount(amount)
- .setMinAmount(minAmount)
- .setPrice(fixedPrice)
- .setPaymentAccountId(paymentAcctId)
- .build();
- return grpcStubs.offersService.createBsqSwapOffer(request).getBsqSwapOffer();
+ public OfferCategory getAvailableOfferCategory(String offerId) {
+ return offersServiceRequest.getAvailableOfferCategory(offerId);
+ }
+
+ public OfferCategory getMyOfferCategory(String offerId) {
+ return offersServiceRequest.getMyOfferCategory(offerId);
+ }
+
+ public OfferInfo createBsqSwapOffer(String direction,
+ long amount,
+ long minAmount,
+ String fixedPrice) {
+ return offersServiceRequest.createBsqSwapOffer(direction,
+ amount,
+ minAmount,
+ fixedPrice);
}
public OfferInfo createFixedPricedOffer(String direction,
@@ -263,7 +262,7 @@ public void cancelOffer(String offerId) {
offersServiceRequest.cancelOffer(offerId);
}
- public BsqSwapOfferInfo getBsqSwapOffer(String offerId) {
+ public OfferInfo getBsqSwapOffer(String offerId) {
return offersServiceRequest.getBsqSwapOffer(offerId);
}
@@ -271,7 +270,7 @@ public OfferInfo getOffer(String offerId) {
return offersServiceRequest.getOffer(offerId);
}
- public BsqSwapOfferInfo getMyBsqSwapOffer(String offerId) {
+ public OfferInfo getMyBsqSwapOffer(String offerId) {
return offersServiceRequest.getMyBsqSwapOffer(offerId);
}
@@ -279,8 +278,8 @@ public OfferInfo getMyOffer(String offerId) {
return offersServiceRequest.getMyOffer(offerId);
}
- public List getBsqSwapOffers(String direction, String currencyCode) {
- return offersServiceRequest.getBsqSwapOffers(direction, currencyCode);
+ public List getBsqSwapOffers(String direction) {
+ return offersServiceRequest.getBsqSwapOffers(direction);
}
public List getOffers(String direction, String currencyCode) {
@@ -303,12 +302,12 @@ public List getBsqOffersSortedByDate() {
return offersServiceRequest.getBsqOffersSortedByDate();
}
- public List getBsqSwapOffersSortedByDate() {
+ public List getBsqSwapOffersSortedByDate() {
return offersServiceRequest.getBsqSwapOffersSortedByDate();
}
- public List getMyBsqSwapOffers(String direction, String currencyCode) {
- return offersServiceRequest.getMyBsqSwapOffers(direction, currencyCode);
+ public List getMyBsqSwapOffers(String direction) {
+ return offersServiceRequest.getMyBsqSwapOffers(direction);
}
public List getMyOffers(String direction, String currencyCode) {
@@ -335,7 +334,7 @@ public List getMyBsqOffersSortedByDate() {
return offersServiceRequest.getMyBsqOffersSortedByDate();
}
- public List getMyBsqSwapBsqOffersSortedByDate() {
+ public List getMyBsqSwapBsqOffersSortedByDate() {
return offersServiceRequest.getMyBsqSwapOffersSortedByDate();
}
@@ -343,45 +342,26 @@ public OfferInfo getMostRecentOffer(String direction, String currencyCode) {
return offersServiceRequest.getMostRecentOffer(direction, currencyCode);
}
- public List sortBsqSwapOffersByDate(List offerInfoList) {
- return offersServiceRequest.sortBsqSwapOffersByDate(offerInfoList);
- }
-
- public List sortOffersByDate(List offerInfoList) {
- return offersServiceRequest.sortOffersByDate(offerInfoList);
+ public List sortBsqSwapOffersByDate(List offers) {
+ return offersServiceRequest.sortOffersByDate(offers);
}
- 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 List sortOffersByDate(List offers) {
+ return offersServiceRequest.sortOffersByDate(offers);
}
public TakeOfferReply getTakeOfferReply(String offerId, String paymentAccountId, String takerFeeCurrencyCode) {
return tradesServiceRequest.getTakeOfferReply(offerId, paymentAccountId, takerFeeCurrencyCode);
}
- public BsqSwapTradeInfo takeBsqSwapOffer(String offerId, String paymentAccountId, String takerFeeCurrencyCode) {
- var reply = getTakeBsqSwapOfferReply(offerId, paymentAccountId, takerFeeCurrencyCode);
- if (reply.hasBsqSwapTrade())
- return reply.getBsqSwapTrade();
- else
- throw new IllegalStateException(reply.getFailureReason().getDescription());
+ public TradeInfo takeBsqSwapOffer(String offerId) {
+ return tradesServiceRequest.takeBsqSwapOffer(offerId);
}
public TradeInfo takeOffer(String offerId, String paymentAccountId, String takerFeeCurrencyCode) {
return tradesServiceRequest.takeOffer(offerId, paymentAccountId, takerFeeCurrencyCode);
}
- public BsqSwapTradeInfo getBsqSwapTrade(String tradeId) {
- return tradesServiceRequest.getBsqSwapTrade(tradeId);
- }
-
public TradeInfo getTrade(String tradeId) {
return tradesServiceRequest.getTrade(tradeId);
}
diff --git a/cli/src/main/java/bisq/cli/opts/AbstractMethodOptionParser.java b/cli/src/main/java/bisq/cli/opts/AbstractMethodOptionParser.java
index 499efba7bdc..2bccab1d098 100644
--- a/cli/src/main/java/bisq/cli/opts/AbstractMethodOptionParser.java
+++ b/cli/src/main/java/bisq/cli/opts/AbstractMethodOptionParser.java
@@ -39,7 +39,7 @@ abstract class AbstractMethodOptionParser implements MethodOpts {
protected final OptionParser parser = new OptionParser();
- // The help option for a specific api method, e.g., takeoffer -help.
+ // The help option for a specific api method, e.g., takeoffer --help.
protected final OptionSpec helpOpt = parser.accepts(OPT_HELP, "Print method help").forHelp();
@Getter
diff --git a/cli/src/main/java/bisq/cli/opts/CancelOfferOptionParser.java b/cli/src/main/java/bisq/cli/opts/CancelOfferOptionParser.java
index c35ffc7bfb4..a18edb84c60 100644
--- a/cli/src/main/java/bisq/cli/opts/CancelOfferOptionParser.java
+++ b/cli/src/main/java/bisq/cli/opts/CancelOfferOptionParser.java
@@ -18,14 +18,7 @@
package bisq.cli.opts;
-import joptsimple.OptionSpec;
-
-import static bisq.cli.opts.OptLabel.OPT_OFFER_ID;
-
-public class CancelOfferOptionParser extends AbstractMethodOptionParser implements MethodOpts {
-
- final OptionSpec offerIdOpt = parser.accepts(OPT_OFFER_ID, "id of offer to cancel")
- .withRequiredArg();
+public class CancelOfferOptionParser extends OfferIdOptionParser implements MethodOpts {
public CancelOfferOptionParser(String[] args) {
super(args);
@@ -34,12 +27,7 @@ public CancelOfferOptionParser(String[] args) {
public CancelOfferOptionParser parse() {
super.parse();
- // Short circuit opt validation if user just wants help.
- if (options.has(helpOpt))
- return this;
-
- if (!options.has(offerIdOpt) || options.valueOf(offerIdOpt).isEmpty())
- throw new IllegalArgumentException("no offer id specified");
+ // Super class will short-circuit parsing if help option is present.
return this;
}
diff --git a/cli/src/main/java/bisq/cli/opts/CreateCryptoCurrencyPaymentAcctOptionParser.java b/cli/src/main/java/bisq/cli/opts/CreateCryptoCurrencyPaymentAcctOptionParser.java
index a37a9f109bb..94db971dba0 100644
--- a/cli/src/main/java/bisq/cli/opts/CreateCryptoCurrencyPaymentAcctOptionParser.java
+++ b/cli/src/main/java/bisq/cli/opts/CreateCryptoCurrencyPaymentAcctOptionParser.java
@@ -24,6 +24,7 @@
import static bisq.cli.opts.OptLabel.OPT_ADDRESS;
import static bisq.cli.opts.OptLabel.OPT_CURRENCY_CODE;
import static bisq.cli.opts.OptLabel.OPT_TRADE_INSTANT;
+import static java.lang.Boolean.FALSE;
public class CreateCryptoCurrencyPaymentAcctOptionParser extends AbstractMethodOptionParser implements MethodOpts {
@@ -39,7 +40,7 @@ public class CreateCryptoCurrencyPaymentAcctOptionParser extends AbstractMethodO
final OptionSpec tradeInstantOpt = parser.accepts(OPT_TRADE_INSTANT, "create trade instant account")
.withOptionalArg()
.ofType(boolean.class)
- .defaultsTo(Boolean.FALSE);
+ .defaultsTo(FALSE);
public CreateCryptoCurrencyPaymentAcctOptionParser(String[] args) {
super(args);
diff --git a/cli/src/main/java/bisq/cli/opts/CreateOfferOptionParser.java b/cli/src/main/java/bisq/cli/opts/CreateOfferOptionParser.java
index 42cf8ad1550..f75ee37db55 100644
--- a/cli/src/main/java/bisq/cli/opts/CreateOfferOptionParser.java
+++ b/cli/src/main/java/bisq/cli/opts/CreateOfferOptionParser.java
@@ -23,12 +23,13 @@
import java.math.BigDecimal;
import static bisq.cli.opts.OptLabel.*;
+import static java.lang.Boolean.FALSE;
import static joptsimple.internal.Strings.EMPTY;
public class CreateOfferOptionParser extends AbstractMethodOptionParser implements MethodOpts {
final OptionSpec paymentAccountIdOpt = parser.accepts(OPT_PAYMENT_ACCOUNT,
- "id of payment account used for offer")
+ "id of payment account used for offer")
.withRequiredArg()
.defaultsTo(EMPTY);
@@ -59,6 +60,11 @@ public class CreateOfferOptionParser extends AbstractMethodOptionParser implemen
.withOptionalArg()
.defaultsTo("btc");
+ final OptionSpec isSwapOpt = parser.accepts(OPT_SWAP, "create bsq swap offer")
+ .withOptionalArg()
+ .ofType(boolean.class)
+ .defaultsTo(FALSE);
+
public CreateOfferOptionParser(String[] args) {
super(args);
}
@@ -70,9 +76,6 @@ public CreateOfferOptionParser parse() {
if (options.has(helpOpt))
return this;
- if (!options.has(paymentAccountIdOpt) || options.valueOf(paymentAccountIdOpt).isEmpty())
- throw new IllegalArgumentException("no payment account id specified");
-
if (!options.has(directionOpt) || options.valueOf(directionOpt).isEmpty())
throw new IllegalArgumentException("no direction (buy|sell) specified");
@@ -82,17 +85,38 @@ public CreateOfferOptionParser parse() {
if (!options.has(amountOpt) || options.valueOf(amountOpt).isEmpty())
throw new IllegalArgumentException("no btc amount specified");
- if (!options.has(mktPriceMarginOpt) && !options.has(fixedPriceOpt))
- throw new IllegalArgumentException("no market price margin or fixed price specified");
+ if (getIsSwap()) {
+ if (!options.valueOf(currencyCodeOpt).equalsIgnoreCase("bsq"))
+ throw new IllegalArgumentException("only bsq swaps are currently supported");
+
+ if (options.has(paymentAccountIdOpt))
+ throw new IllegalArgumentException("cannot use a payment account id in bsq swap offer");
+
+ if (options.has(mktPriceMarginOpt))
+ throw new IllegalArgumentException("cannot use a market price margin in bsq swap offer");
+
+ if (options.has(securityDepositOpt))
+ throw new IllegalArgumentException("cannot use a security deposit in bsq swap offer");
- if (options.has(mktPriceMarginOpt) && options.valueOf(mktPriceMarginOpt).isEmpty())
- throw new IllegalArgumentException("no market price margin specified");
+ if (!options.has(fixedPriceOpt) || options.valueOf(fixedPriceOpt).isEmpty())
+ throw new IllegalArgumentException("no fixed price specified");
- if (options.has(fixedPriceOpt) && options.valueOf(fixedPriceOpt).isEmpty())
- throw new IllegalArgumentException("no fixed price specified");
+ } else {
+ if (!options.has(paymentAccountIdOpt) || options.valueOf(paymentAccountIdOpt).isEmpty())
+ throw new IllegalArgumentException("no payment account id specified");
- if (!options.has(securityDepositOpt) || options.valueOf(securityDepositOpt).isEmpty())
- throw new IllegalArgumentException("no security deposit specified");
+ if (!options.has(mktPriceMarginOpt) && !options.has(fixedPriceOpt))
+ throw new IllegalArgumentException("no market price margin or fixed price specified");
+
+ if (options.has(mktPriceMarginOpt) && options.valueOf(mktPriceMarginOpt).isEmpty())
+ throw new IllegalArgumentException("no market price margin specified");
+
+ if (options.has(fixedPriceOpt) && options.valueOf(fixedPriceOpt).isEmpty())
+ throw new IllegalArgumentException("no fixed price specified");
+
+ if (!options.has(securityDepositOpt) || options.valueOf(securityDepositOpt).isEmpty())
+ throw new IllegalArgumentException("no security deposit specified");
+ }
return this;
}
@@ -141,4 +165,8 @@ public String getSecurityDeposit() {
public String getMakerFeeCurrencyCode() {
return options.has(makerFeeCurrencyCodeOpt) ? options.valueOf(makerFeeCurrencyCodeOpt) : "btc";
}
+
+ public boolean getIsSwap() {
+ return options.valueOf(isSwapOpt);
+ }
}
diff --git a/cli/src/main/java/bisq/cli/opts/CreatePaymentAcctOptionParser.java b/cli/src/main/java/bisq/cli/opts/CreatePaymentAcctOptionParser.java
index fe91924bb41..c4b52229664 100644
--- a/cli/src/main/java/bisq/cli/opts/CreatePaymentAcctOptionParser.java
+++ b/cli/src/main/java/bisq/cli/opts/CreatePaymentAcctOptionParser.java
@@ -29,7 +29,7 @@
public class CreatePaymentAcctOptionParser extends AbstractMethodOptionParser implements MethodOpts {
final OptionSpec paymentAcctFormPathOpt = parser.accepts(OPT_PAYMENT_ACCOUNT_FORM,
- "path to json payment account form")
+ "path to json payment account form")
.withRequiredArg();
public CreatePaymentAcctOptionParser(String[] args) {
diff --git a/cli/src/main/java/bisq/cli/opts/EditOfferOptionParser.java b/cli/src/main/java/bisq/cli/opts/EditOfferOptionParser.java
index 288f1a9f40d..ee994e77786 100644
--- a/cli/src/main/java/bisq/cli/opts/EditOfferOptionParser.java
+++ b/cli/src/main/java/bisq/cli/opts/EditOfferOptionParser.java
@@ -24,7 +24,10 @@
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 java.lang.String.format;
@@ -32,26 +35,23 @@
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_OFF = 0;
static int OPT_ENABLE_IGNORED = -1;
- final OptionSpec offerIdOpt = parser.accepts(OPT_OFFER_ID, "id of offer to cancel")
- .withRequiredArg();
-
final OptionSpec fixedPriceOpt = parser.accepts(OPT_FIXED_PRICE, "fixed btc price")
.withOptionalArg()
.defaultsTo("0");
final OptionSpec mktPriceMarginOpt = parser.accepts(OPT_MKT_PRICE_MARGIN,
- "market btc price margin (%)")
+ "market btc price margin (%)")
.withOptionalArg()
.defaultsTo("0.00");
final OptionSpec 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()
.defaultsTo("0");
@@ -59,25 +59,20 @@ public class EditOfferOptionParser extends AbstractMethodOptionParser implements
// activation state). For this reason, a boolean type is not used (can only be
// true or false).
final OptionSpec enableOpt = parser.accepts(OPT_ENABLE,
- "enable or disable offer")
+ "enable or disable offer")
.withOptionalArg()
.ofType(String.class);
private EditOfferRequest.EditType offerEditType;
public EditOfferOptionParser(String[] args) {
- super(args);
+ super(args, true);
}
public EditOfferOptionParser parse() {
super.parse();
- // Short circuit opt validation if user just wants help.
- if (options.has(helpOpt))
- return this;
-
- if (!options.has(offerIdOpt) || options.valueOf(offerIdOpt).isEmpty())
- throw new IllegalArgumentException("no offer id specified");
+ // Super class will short-circuit parsing if help option is present.
boolean hasNoEditDetails = !options.has(fixedPriceOpt)
&& !options.has(mktPriceMarginOpt)
@@ -201,10 +196,6 @@ public EditOfferOptionParser parse() {
return this;
}
- public String getOfferId() {
- return options.valueOf(offerIdOpt);
- }
-
public String getFixedPrice() {
if (offerEditType.equals(FIXED_PRICE_ONLY) || offerEditType.equals(FIXED_PRICE_AND_ACTIVATION_STATE)) {
return options.has(fixedPriceOpt) ? options.valueOf(fixedPriceOpt) : "0";
diff --git a/cli/src/main/java/bisq/cli/opts/GetPaymentAcctFormOptionParser.java b/cli/src/main/java/bisq/cli/opts/GetPaymentAcctFormOptionParser.java
index 508069c2f30..bec9044f264 100644
--- a/cli/src/main/java/bisq/cli/opts/GetPaymentAcctFormOptionParser.java
+++ b/cli/src/main/java/bisq/cli/opts/GetPaymentAcctFormOptionParser.java
@@ -25,7 +25,7 @@
public class GetPaymentAcctFormOptionParser extends AbstractMethodOptionParser implements MethodOpts {
final OptionSpec 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();
public GetPaymentAcctFormOptionParser(String[] args) {
diff --git a/cli/src/main/java/bisq/cli/opts/GetOfferOptionParser.java b/cli/src/main/java/bisq/cli/opts/OfferIdOptionParser.java
similarity index 71%
rename from cli/src/main/java/bisq/cli/opts/GetOfferOptionParser.java
rename to cli/src/main/java/bisq/cli/opts/OfferIdOptionParser.java
index 1a849654cf7..ccf04026523 100644
--- a/cli/src/main/java/bisq/cli/opts/GetOfferOptionParser.java
+++ b/cli/src/main/java/bisq/cli/opts/OfferIdOptionParser.java
@@ -22,16 +22,26 @@
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 offerIdOpt = parser.accepts(OPT_OFFER_ID, "id of offer to get")
+ final OptionSpec offerIdOpt = parser.accepts(OPT_OFFER_ID, "id of offer")
.withRequiredArg();
- public GetOfferOptionParser(String[] args) {
+ public OfferIdOptionParser(String[] args) {
+ this(args, false);
+ }
+
+ public OfferIdOptionParser(String[] args, boolean allowsUnrecognizedOptions) {
super(args);
+ if (allowsUnrecognizedOptions)
+ this.parser.allowsUnrecognizedOptions();
}
- public GetOfferOptionParser parse() {
+ public OfferIdOptionParser parse() {
super.parse();
// Short circuit opt validation if user just wants help.
diff --git a/cli/src/main/java/bisq/cli/opts/OptLabel.java b/cli/src/main/java/bisq/cli/opts/OptLabel.java
index 70dda3e6fc3..7dc78165d7a 100644
--- a/cli/src/main/java/bisq/cli/opts/OptLabel.java
+++ b/cli/src/main/java/bisq/cli/opts/OptLabel.java
@@ -44,6 +44,7 @@ public class OptLabel {
public final static String OPT_REGISTRATION_KEY = "registration-key";
public final static String OPT_SECURITY_DEPOSIT = "security-deposit";
public final static String OPT_SHOW_CONTRACT = "show-contract";
+ public final static String OPT_SWAP = "swap";
public final static String OPT_TRADE_ID = "trade-id";
public final static String OPT_TRADE_INSTANT = "trade-instant";
public final static String OPT_TIMEOUT = "timeout";
diff --git a/cli/src/main/java/bisq/cli/opts/SetTxFeeRateOptionParser.java b/cli/src/main/java/bisq/cli/opts/SetTxFeeRateOptionParser.java
index f7ed113cb3c..be0132b5fee 100644
--- a/cli/src/main/java/bisq/cli/opts/SetTxFeeRateOptionParser.java
+++ b/cli/src/main/java/bisq/cli/opts/SetTxFeeRateOptionParser.java
@@ -25,7 +25,7 @@
public class SetTxFeeRateOptionParser extends AbstractMethodOptionParser implements MethodOpts {
final OptionSpec feeRateOpt = parser.accepts(OPT_TX_FEE_RATE,
- "tx fee rate preference (sats/byte)")
+ "tx fee rate preference (sats/byte)")
.withRequiredArg();
public SetTxFeeRateOptionParser(String[] args) {
diff --git a/cli/src/main/java/bisq/cli/opts/TakeOfferOptionParser.java b/cli/src/main/java/bisq/cli/opts/TakeOfferOptionParser.java
index 67fbdd8c86d..6f848f8e413 100644
--- a/cli/src/main/java/bisq/cli/opts/TakeOfferOptionParser.java
+++ b/cli/src/main/java/bisq/cli/opts/TakeOfferOptionParser.java
@@ -21,13 +21,9 @@
import joptsimple.OptionSpec;
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;
-public class TakeOfferOptionParser extends AbstractMethodOptionParser implements MethodOpts {
-
- final OptionSpec offerIdOpt = parser.accepts(OPT_OFFER_ID, "id of offer to take")
- .withRequiredArg();
+public class TakeOfferOptionParser extends OfferIdOptionParser implements MethodOpts {
final OptionSpec paymentAccountIdOpt = parser.accepts(OPT_PAYMENT_ACCOUNT, "id of payment account used for trade")
.withRequiredArg();
@@ -37,18 +33,13 @@ public class TakeOfferOptionParser extends AbstractMethodOptionParser implements
.defaultsTo("btc");
public TakeOfferOptionParser(String[] args) {
- super(args);
+ super(args, true);
}
public TakeOfferOptionParser parse() {
super.parse();
- // Short circuit opt validation if user just wants help.
- if (options.has(helpOpt))
- return this;
-
- if (!options.has(offerIdOpt) || options.valueOf(offerIdOpt).isEmpty())
- throw new IllegalArgumentException("no offer id specified");
+ // Super class will short-circuit parsing if help option is present.
if (!options.has(paymentAccountIdOpt) || options.valueOf(paymentAccountIdOpt).isEmpty())
throw new IllegalArgumentException("no payment account id specified");
@@ -56,10 +47,6 @@ public TakeOfferOptionParser parse() {
return this;
}
- public String getOfferId() {
- return options.valueOf(offerIdOpt);
- }
-
public String getPaymentAccountId() {
return options.valueOf(paymentAccountIdOpt);
}
diff --git a/cli/src/main/java/bisq/cli/request/OffersServiceRequest.java b/cli/src/main/java/bisq/cli/request/OffersServiceRequest.java
index 259ff8e142d..c3cd9cdc799 100644
--- a/cli/src/main/java/bisq/cli/request/OffersServiceRequest.java
+++ b/cli/src/main/java/bisq/cli/request/OffersServiceRequest.java
@@ -17,12 +17,14 @@
package bisq.cli.request;
-import bisq.proto.grpc.BsqSwapOfferInfo;
import bisq.proto.grpc.CancelOfferRequest;
+import bisq.proto.grpc.CreateBsqSwapOfferRequest;
import bisq.proto.grpc.CreateOfferRequest;
import bisq.proto.grpc.EditOfferRequest;
+import bisq.proto.grpc.GetBsqSwapOffersRequest;
import bisq.proto.grpc.GetMyOfferRequest;
import bisq.proto.grpc.GetMyOffersRequest;
+import bisq.proto.grpc.GetOfferCategoryRequest;
import bisq.proto.grpc.GetOfferRequest;
import bisq.proto.grpc.GetOffersRequest;
import bisq.proto.grpc.OfferInfo;
@@ -37,6 +39,7 @@
import static bisq.proto.grpc.EditOfferRequest.EditType.FIXED_PRICE_ONLY;
import static bisq.proto.grpc.EditOfferRequest.EditType.MKT_PRICE_MARGIN_ONLY;
import static bisq.proto.grpc.EditOfferRequest.EditType.TRIGGER_PRICE_ONLY;
+import static bisq.proto.grpc.GetOfferCategoryReply.OfferCategory;
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;
import static protobuf.OfferDirection.BUY;
@@ -60,6 +63,27 @@ public OffersServiceRequest(GrpcStubs grpcStubs) {
this.grpcStubs = grpcStubs;
}
+ public OfferCategory getAvailableOfferCategory(String offerId) {
+ return getOfferCategory(offerId, false);
+ }
+
+ public OfferCategory getMyOfferCategory(String offerId) {
+ return getOfferCategory(offerId, true);
+ }
+
+ public OfferInfo createBsqSwapOffer(String direction,
+ long amount,
+ long minAmount,
+ String fixedPrice) {
+ var request = CreateBsqSwapOfferRequest.newBuilder()
+ .setDirection(direction)
+ .setAmount(amount)
+ .setMinAmount(minAmount)
+ .setPrice(fixedPrice)
+ .build();
+ return grpcStubs.offersService.createBsqSwapOffer(request).getBsqSwapOffer();
+ }
+
@SuppressWarnings("unused")
public OfferInfo createFixedPricedOffer(String direction,
String currencyCode,
@@ -210,7 +234,7 @@ public void cancelOffer(String offerId) {
grpcStubs.offersService.cancelOffer(request);
}
- public BsqSwapOfferInfo getBsqSwapOffer(String offerId) {
+ public OfferInfo getBsqSwapOffer(String offerId) {
var request = GetOfferRequest.newBuilder()
.setId(offerId)
.build();
@@ -224,7 +248,7 @@ public OfferInfo getOffer(String offerId) {
return grpcStubs.offersService.getOffer(request).getOffer();
}
- public BsqSwapOfferInfo getMyBsqSwapOffer(String offerId) {
+ public OfferInfo getMyBsqSwapOffer(String offerId) {
var request = GetMyOfferRequest.newBuilder()
.setId(offerId)
.build();
@@ -239,10 +263,9 @@ public OfferInfo getMyOffer(String offerId) {
return grpcStubs.offersService.getMyOffer(request).getOffer();
}
- public List getBsqSwapOffers(String direction, String currencyCode) {
- var request = GetOffersRequest.newBuilder()
+ public List getBsqSwapOffers(String direction) {
+ var request = GetBsqSwapOffersRequest.newBuilder()
.setDirection(direction)
- .setCurrencyCode(currencyCode)
.build();
return grpcStubs.offersService.getBsqSwapOffers(request).getBsqSwapOffersList();
@@ -278,11 +301,11 @@ public List getOffersSortedByDate(String direction, String currencyCo
return offers.isEmpty() ? offers : sortOffersByDate(offers);
}
- public List getBsqSwapOffersSortedByDate() {
- ArrayList offers = new ArrayList<>();
- offers.addAll(getBsqSwapOffers(BUY.name(), "BSQ"));
- offers.addAll(getBsqSwapOffers(SELL.name(), "BSQ"));
- return sortBsqSwapOffersByDate(offers);
+ public List getBsqSwapOffersSortedByDate() {
+ ArrayList offers = new ArrayList<>();
+ offers.addAll(getBsqSwapOffers(BUY.name()));
+ offers.addAll(getBsqSwapOffers(SELL.name()));
+ return sortOffersByDate(offers);
}
public List getBsqOffersSortedByDate() {
@@ -292,10 +315,9 @@ public List getBsqOffersSortedByDate() {
return sortOffersByDate(offers);
}
- public List getMyBsqSwapOffers(String direction, String currencyCode) {
- var request = GetMyOffersRequest.newBuilder()
+ public List getMyBsqSwapOffers(String direction) {
+ var request = GetBsqSwapOffersRequest.newBuilder()
.setDirection(direction)
- .setCurrencyCode(currencyCode)
.build();
return grpcStubs.offersService.getMyBsqSwapOffers(request).getBsqSwapOffersList();
}
@@ -344,11 +366,11 @@ public List getMyBsqOffersSortedByDate() {
return sortOffersByDate(offers);
}
- public List getMyBsqSwapOffersSortedByDate() {
- ArrayList offers = new ArrayList<>();
- offers.addAll(getMyBsqSwapOffers(BUY.name(), "BSQ"));
- offers.addAll(getMyBsqSwapOffers(SELL.name(), "BSQ"));
- return sortBsqSwapOffersByDate(offers);
+ public List getMyBsqSwapOffersSortedByDate() {
+ ArrayList offers = new ArrayList<>();
+ offers.addAll(getMyBsqSwapOffers(BUY.name()));
+ offers.addAll(getMyBsqSwapOffers(SELL.name()));
+ return sortOffersByDate(offers);
}
public OfferInfo getMostRecentOffer(String direction, String currencyCode) {
@@ -356,19 +378,20 @@ public OfferInfo getMostRecentOffer(String direction, String currencyCode) {
return offers.isEmpty() ? null : offers.get(offers.size() - 1);
}
- public List sortBsqSwapOffersByDate(List offerInfoList) {
- return offerInfoList.stream()
- .sorted(comparing(BsqSwapOfferInfo::getDate))
- .collect(toList());
-
- }
-
public List sortOffersByDate(List offerInfoList) {
return offerInfoList.stream()
.sorted(comparing(OfferInfo::getDate))
.collect(toList());
}
+ private OfferCategory getOfferCategory(String offerId, boolean isMyOffer) {
+ var request = GetOfferCategoryRequest.newBuilder()
+ .setId(offerId)
+ .setIsMyOffer(isMyOffer)
+ .build();
+ return grpcStubs.offersService.getOfferCategory(request).getOfferCategory();
+ }
+
private static boolean isSupportedCryptoCurrency(String currencyCode) {
return getSupportedCryptoCurrencies().contains(currencyCode.toUpperCase());
}
diff --git a/cli/src/main/java/bisq/cli/request/TradesServiceRequest.java b/cli/src/main/java/bisq/cli/request/TradesServiceRequest.java
index 97d7d2a5efe..cf95506615e 100644
--- a/cli/src/main/java/bisq/cli/request/TradesServiceRequest.java
+++ b/cli/src/main/java/bisq/cli/request/TradesServiceRequest.java
@@ -17,7 +17,6 @@
package bisq.cli.request;
-import bisq.proto.grpc.BsqSwapTradeInfo;
import bisq.proto.grpc.ConfirmPaymentReceivedRequest;
import bisq.proto.grpc.ConfirmPaymentStartedRequest;
import bisq.proto.grpc.GetTradeRequest;
@@ -48,19 +47,20 @@ public TakeOfferReply getTakeOfferReply(String offerId, String paymentAccountId,
return grpcStubs.tradesService.takeOffer(request);
}
- public TradeInfo takeOffer(String offerId, String paymentAccountId, String takerFeeCurrencyCode) {
- var reply = getTakeOfferReply(offerId, paymentAccountId, takerFeeCurrencyCode);
+ public TradeInfo takeBsqSwapOffer(String offerId) {
+ var reply = getTakeOfferReply(offerId, "", "");
if (reply.hasTrade())
return reply.getTrade();
else
throw new IllegalStateException(reply.getFailureReason().getDescription());
}
- public BsqSwapTradeInfo getBsqSwapTrade(String tradeId) {
- var request = GetTradeRequest.newBuilder()
- .setTradeId(tradeId)
- .build();
- return grpcStubs.tradesService.getBsqSwapTrade(request).getBsqSwapTrade();
+ public TradeInfo takeOffer(String offerId, String paymentAccountId, String takerFeeCurrencyCode) {
+ var reply = getTakeOfferReply(offerId, paymentAccountId, takerFeeCurrencyCode);
+ if (reply.hasTrade())
+ return reply.getTrade();
+ else
+ throw new IllegalStateException(reply.getFailureReason().getDescription());
}
public TradeInfo getTrade(String tradeId) {
diff --git a/cli/src/main/java/bisq/cli/table/builder/AbstractTradeListBuilder.java b/cli/src/main/java/bisq/cli/table/builder/AbstractTradeListBuilder.java
index 23a265a45ce..5c7b109e574 100644
--- a/cli/src/main/java/bisq/cli/table/builder/AbstractTradeListBuilder.java
+++ b/cli/src/main/java/bisq/cli/table/builder/AbstractTradeListBuilder.java
@@ -102,6 +102,15 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder {
@Nullable
protected final Column colAltcoinReceiveAddressColumn;
+ // BSQ swap trade detail specific columns
+
+ @Nullable
+ protected final Column status;
+ @Nullable
+ protected final Column colTxId;
+ @Nullable
+ protected final Column colNumConfirmations;
+
AbstractTradeListBuilder(TableType tableType, List> protos) {
super(tableType, protos);
validate();
@@ -125,7 +134,9 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder {
this.colRole = colSupplier.roleColumn.get();
this.colOfferType = colSupplier.offerTypeColumn.get();
this.colStatusDescription = colSupplier.statusDescriptionColumn.get();
- // Trade detail specific columns
+
+ // Trade detail specific columns, some in common with BSQ swap trades detail.
+
this.colIsDepositPublished = colSupplier.depositPublishedColumn.get();
this.colIsDepositConfirmed = colSupplier.depositConfirmedColumn.get();
this.colIsPayoutPublished = colSupplier.payoutPublishedColumn.get();
@@ -135,6 +146,12 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder {
this.colIsPaymentSent = colSupplier.paymentSentColumn.get();
this.colIsPaymentReceived = colSupplier.paymentReceivedColumn.get();
this.colAltcoinReceiveAddressColumn = colSupplier.altcoinReceiveAddressColumn.get();
+
+ // BSQ swap trade detail specific columns
+
+ this.status = colSupplier.bsqSwapStatusColumn.get();
+ this.colTxId = colSupplier.bsqSwapTxIdColumn.get();
+ this.colNumConfirmations = colSupplier.numConfirmationsColumn.get();
}
protected void validate() {
@@ -149,9 +166,8 @@ protected void validate() {
// Helper Functions
private final Supplier isTradeDetailTblBuilder = () -> tableType.equals(TRADE_DETAIL_TBL);
-
protected final Predicate isFiatTrade = (t) -> isFiatOffer.test(t.getOffer());
-
+ protected final Predicate isBsqSwapTrade = (t) -> t.getOffer().getIsBsqSwapOffer();
protected final Predicate isTaker = (t) -> t.getRole().toLowerCase().contains("taker");
// Column Value Functions
@@ -185,7 +201,6 @@ protected void validate() {
}
};
- // TODO Move to TradeUtil ?
protected final Function toPriceDeviation = (t) ->
t.getOffer().getUseMarketBasedPrice()
? formatToPercent(t.getOffer().getMarketPriceMargin())
@@ -196,8 +211,6 @@ protected void validate() {
? t.getTxFeeAsLong()
: t.getOffer().getTxFee();
-
- // TODO Move to TradeUtil ?
protected final BiFunction toTradeFeeBsq = (t, isMyOffer) -> {
if (isMyOffer) {
return t.getOffer().getIsCurrencyForMakerFeeBtc()
@@ -210,7 +223,6 @@ protected void validate() {
}
};
- // TODO Move to TradeUtil ?
protected final BiFunction toTradeFeeBtc = (t, isMyOffer) -> {
if (isMyOffer) {
return t.getOffer().getIsCurrencyForMakerFeeBtc()
@@ -223,12 +235,18 @@ protected void validate() {
}
};
- protected final Function toMyMakerOrTakerFee = (t) ->
- isTaker.test(t)
+ protected final Function toMyMakerOrTakerFee = (t) -> {
+ if (isBsqSwapTrade.test(t)) {
+ return isTaker.test(t)
+ ? t.getBsqSwapTradeInfo().getBsqTakerTradeFee()
+ : t.getBsqSwapTradeInfo().getBsqMakerTradeFee();
+ } else {
+ return isTaker.test(t)
? t.getTakerFeeAsLong()
: t.getOffer().getMakerFee();
+ }
+ };
- // TODO Move to TradeUtil ? SEE ClosedTradesViewModel # getDirectionLabel
protected final Function toOfferType = (t) -> {
if (isFiatTrade.test(t)) {
return t.getOffer().getDirection() + " " + t.getOffer().getBaseCurrencyCode();
@@ -267,7 +285,7 @@ protected void validate() {
}
};
- // TODO Stuff to move into bisq/cli/CurrencyFormat.java ?
+ // TODO Move to bisq/cli/CurrencyFormat.java ?
public static String formatToPercent(double value) {
DecimalFormat decimalFormat = new DecimalFormat("#.##");
diff --git a/cli/src/main/java/bisq/cli/table/builder/TableBuilderConstants.java b/cli/src/main/java/bisq/cli/table/builder/TableBuilderConstants.java
index 1ea28b63ecc..b29aa3e3ec9 100644
--- a/cli/src/main/java/bisq/cli/table/builder/TableBuilderConstants.java
+++ b/cli/src/main/java/bisq/cli/table/builder/TableBuilderConstants.java
@@ -35,6 +35,7 @@ class TableBuilderConstants {
static final String COL_HEADER_LOCKUP_BONDS_BALANCE = "Lockup Bonds Balance";
static final String COL_HEADER_UNLOCKING_BONDS_BALANCE = "Unlocking Bonds Balance";
static final String COL_HEADER_UNVERIFIED_BALANCE = "Unverified Balance";
+ static final String COL_HEADER_BSQ_SWAP_TRADE_ROLE = "My BSQ Swap Role";
static final String COL_HEADER_BUYER_DEPOSIT = "Buyer Deposit";
static final String COL_HEADER_SELLER_DEPOSIT = "Seller Deposit";
static final String COL_HEADER_CONFIRMATIONS = "Confirmations";
@@ -65,8 +66,6 @@ class TableBuilderConstants {
static final String COL_HEADER_TRADE_ID = "Trade ID";
static final String COL_HEADER_TRADE_ROLE = "My Role";
static final String COL_HEADER_TRADE_SHORT_ID = "ID";
- @Deprecated
- static final String COL_HEADER_TRADE_TX_FEE = "Tx Fee(BTC)";
static final String COL_HEADER_TRADE_MAKER_FEE = "Maker Fee(%-3s)";
static final String COL_HEADER_TRADE_TAKER_FEE = "Taker Fee(%-3s)";
static final String COL_HEADER_TRADE_FEE = "Trade Fee";
diff --git a/cli/src/main/java/bisq/cli/table/builder/TradeDetailTableBuilder.java b/cli/src/main/java/bisq/cli/table/builder/TradeDetailTableBuilder.java
index 693a0c916a0..9d577ca1f6d 100644
--- a/cli/src/main/java/bisq/cli/table/builder/TradeDetailTableBuilder.java
+++ b/cli/src/main/java/bisq/cli/table/builder/TradeDetailTableBuilder.java
@@ -17,10 +17,16 @@
package bisq.cli.table.builder;
+import bisq.proto.grpc.TradeInfo;
+
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Predicate;
import static bisq.cli.table.builder.TableType.TRADE_DETAIL_TBL;
+import static java.lang.String.format;
+import static protobuf.BsqSwapTrade.State.COMPLETED;
+import static protobuf.BsqSwapTrade.State.PREPARATION;
@@ -30,8 +36,12 @@
/**
* Builds a {@code bisq.cli.table.Table} from a {@code bisq.proto.grpc.TradeInfo} object.
*/
+@SuppressWarnings("ConstantConditions")
class TradeDetailTableBuilder extends AbstractTradeListBuilder {
+ private final Predicate isPendingBsqSwap = (t) -> t.getState().equals(PREPARATION.name());
+ private final Predicate isCompletedBsqSwap = (t) -> t.getState().equals(COMPLETED.name());
+
TradeDetailTableBuilder(List> protos) {
super(TRADE_DETAIL_TBL, protos);
}
@@ -41,33 +51,70 @@ class TradeDetailTableBuilder extends AbstractTradeListBuilder {
* @return Table containing one row
*/
public Table build() {
- populateColumns();
- List> columns = defineColumnList();
+ // A trade detail table only has one row.
+ var trade = trades.get(0);
+ populateColumns(trade);
+ List> columns = defineColumnList(trade);
return new Table(columns.toArray(new Column>[0]));
}
- private void populateColumns() {
- trades.stream().forEachOrdered(t -> {
- colTradeId.addRow(t.getShortId());
- colRole.addRow(t.getRole());
- colPrice.addRow(t.getTradePrice());
- colAmountInBtc.addRow(toAmount.apply(t));
- colMinerTxFee.addRow(toMyMinerTxFee.apply(t));
- colBisqTradeFee.addRow(toMyMakerOrTakerFee.apply(t));
- colIsDepositPublished.addRow(t.getIsDepositPublished());
- colIsDepositConfirmed.addRow(t.getIsDepositConfirmed());
- colTradeCost.addRow(toTradeVolume.apply(t));
- colIsPaymentSent.addRow(t.getIsFiatSent());
- colIsPaymentReceived.addRow(t.getIsFiatReceived());
- colIsPayoutPublished.addRow(t.getIsPayoutPublished());
- colIsFundsWithdrawn.addRow(t.getIsWithdrawn());
-
- if (colAltcoinReceiveAddressColumn != null)
- colAltcoinReceiveAddressColumn.addRow(toAltcoinReceiveAddress.apply(t));
- });
+ private void populateColumns(TradeInfo trade) {
+ if (isBsqSwapTrade.test(trade)) {
+ var isPending = isPendingBsqSwap.test(trade);
+ var isCompleted = isCompletedBsqSwap.test(trade);
+ if (isPending == isCompleted)
+ throw new IllegalStateException(
+ format("programmer error: trade must be either pending or completed, is pending=%s and completed=%s",
+ isPending,
+ isCompleted));
+ populateBsqSwapTradeColumns(trade);
+ } else {
+ populateBisqV1TradeColumns(trade);
+ }
}
- private List> defineColumnList() {
+ private void populateBisqV1TradeColumns(TradeInfo trade) {
+ colTradeId.addRow(trade.getShortId());
+ colRole.addRow(trade.getRole());
+ colPrice.addRow(trade.getTradePrice());
+ colAmountInBtc.addRow(toAmount.apply(trade));
+ colMinerTxFee.addRow(toMyMinerTxFee.apply(trade));
+ colBisqTradeFee.addRow(toMyMakerOrTakerFee.apply(trade));
+ colIsDepositPublished.addRow(trade.getIsDepositPublished());
+ colIsDepositConfirmed.addRow(trade.getIsDepositConfirmed());
+ colTradeCost.addRow(toTradeVolume.apply(trade));
+ colIsPaymentSent.addRow(trade.getIsFiatSent());
+ colIsPaymentReceived.addRow(trade.getIsFiatReceived());
+ colIsPayoutPublished.addRow(trade.getIsPayoutPublished());
+ colIsFundsWithdrawn.addRow(trade.getIsWithdrawn());
+ if (colAltcoinReceiveAddressColumn != null)
+ colAltcoinReceiveAddressColumn.addRow(toAltcoinReceiveAddress.apply(trade));
+ }
+
+ private void populateBsqSwapTradeColumns(TradeInfo trade) {
+ colTradeId.addRow(trade.getShortId());
+ colRole.addRow(trade.getRole());
+ colPrice.addRow(trade.getTradePrice());
+ colAmountInBtc.addRow(toAmount.apply(trade));
+ colMinerTxFee.addRow(toMyMinerTxFee.apply(trade));
+ colBisqTradeFee.addRow(toMyMakerOrTakerFee.apply(trade));
+ colTradeCost.addRow(toTradeVolume.apply(trade));
+
+ var isCompleted = isCompletedBsqSwap.test(trade);
+ status.addRow(isCompleted ? "COMPLETED" : "PENDING");
+ if (isCompleted) {
+ colTxId.addRow(trade.getBsqSwapTradeInfo().getTxId());
+ colNumConfirmations.addRow(trade.getBsqSwapTradeInfo().getNumConfirmations());
+ }
+ }
+
+ private List> defineColumnList(TradeInfo trade) {
+ return isBsqSwapTrade.test(trade)
+ ? getBsqSwapTradeColumnList(isCompletedBsqSwap.test(trade))
+ : getBisqV1TradeColumnList();
+ }
+
+ private List> getBisqV1TradeColumnList() {
List> columns = new ArrayList<>() {{
add(colTradeId);
add(colRole);
@@ -89,4 +136,25 @@ private List> defineColumnList() {
return columns;
}
+
+ private List> getBsqSwapTradeColumnList(boolean isCompleted) {
+ List> columns = new ArrayList<>() {{
+ add(colTradeId);
+ add(colRole);
+ add(colPrice.asStringColumn());
+ add(colAmountInBtc.asStringColumn());
+ add(colMinerTxFee.asStringColumn());
+ add(colBisqTradeFee.asStringColumn());
+ add(colTradeCost.asStringColumn());
+ add(status);
+ }};
+
+ if (isCompleted)
+ columns.add(colTxId);
+
+ if (!colNumConfirmations.isEmpty())
+ columns.add(colNumConfirmations.asStringColumn());
+
+ return columns;
+ }
}
diff --git a/cli/src/main/java/bisq/cli/table/builder/TradeTableColumnSupplier.java b/cli/src/main/java/bisq/cli/table/builder/TradeTableColumnSupplier.java
index 967ee1779f6..ae03cb14e87 100644
--- a/cli/src/main/java/bisq/cli/table/builder/TradeTableColumnSupplier.java
+++ b/cli/src/main/java/bisq/cli/table/builder/TradeTableColumnSupplier.java
@@ -40,6 +40,7 @@
import static bisq.cli.table.column.Column.JUSTIFICATION.LEFT;
import static bisq.cli.table.column.Column.JUSTIFICATION.RIGHT;
import static bisq.cli.table.column.FiatColumn.DISPLAY_MODE.VOLUME;
+import static java.lang.String.format;
@@ -49,6 +50,7 @@
import bisq.cli.table.column.Column;
import bisq.cli.table.column.FiatColumn;
import bisq.cli.table.column.Iso8601DateTimeColumn;
+import bisq.cli.table.column.LongColumn;
import bisq.cli.table.column.MixedPriceColumn;
import bisq.cli.table.column.MixedTradeFeeColumn;
import bisq.cli.table.column.MixedVolumeColumn;
@@ -79,7 +81,10 @@ public TradeTableColumnSupplier(TableType tableType, List trades) {
private final Supplier firstRow = () -> getTrades().get(0);
private final Predicate isFiatOffer = (o) -> o.getBaseCurrencyCode().equals("BTC");
private final Predicate isFiatTrade = (t) -> isFiatOffer.test(t.getOffer());
+ private final Predicate isBsqSwapTrade = (t) -> t.getOffer().getIsBsqSwapOffer();
private final Predicate isTaker = (t) -> t.getRole().toLowerCase().contains("taker");
+ private final Supplier isSwapTradeDetail = () ->
+ isTradeDetailTblBuilder.get() && isBsqSwapTrade.test(firstRow.get());
final Supplier tradeIdColumn = () -> isTradeDetailTblBuilder.get()
? new StringColumn(COL_HEADER_TRADE_SHORT_ID)
@@ -95,8 +100,8 @@ public TradeTableColumnSupplier(TableType tableType, List trades) {
private final Function> toDetailedPriceColumn = (t) -> {
String colHeader = isFiatTrade.test(t)
- ? String.format(COL_HEADER_DETAILED_PRICE, t.getOffer().getCounterCurrencyCode())
- : String.format(COL_HEADER_DETAILED_PRICE_OF_ALTCOIN, t.getOffer().getBaseCurrencyCode());
+ ? format(COL_HEADER_DETAILED_PRICE, t.getOffer().getCounterCurrencyCode())
+ : format(COL_HEADER_DETAILED_PRICE_OF_ALTCOIN, t.getOffer().getBaseCurrencyCode());
return isFiatTrade.test(t)
? new FiatColumn(colHeader)
: new AltcoinColumn(colHeader);
@@ -116,7 +121,7 @@ public TradeTableColumnSupplier(TableType tableType, List trades) {
private final Function> toDetailedAmountColumn = (t) -> {
String headerCurrencyCode = t.getOffer().getBaseCurrencyCode();
- String colHeader = String.format(COL_HEADER_DETAILED_AMOUNT, headerCurrencyCode);
+ String colHeader = format(COL_HEADER_DETAILED_AMOUNT, headerCurrencyCode);
return isFiatTrade.test(t)
? new SatoshiColumn(colHeader)
: new AltcoinColumn(colHeader, ALTCOIN_OFFER_VOLUME);
@@ -142,10 +147,14 @@ public TradeTableColumnSupplier(TableType tableType, List trades) {
? null
: new StringColumn(COL_HEADER_PAYMENT_METHOD, LEFT);
- final Supplier roleColumn = () ->
- isTradeDetailTblBuilder.get() || isOpenTradeTblBuilder.get() || isFailedTradeTblBuilder.get()
+ final Supplier roleColumn = () -> {
+ if (isSwapTradeDetail.get())
+ return new StringColumn(COL_HEADER_BSQ_SWAP_TRADE_ROLE);
+ else
+ return isTradeDetailTblBuilder.get() || isOpenTradeTblBuilder.get() || isFailedTradeTblBuilder.get()
? new StringColumn(COL_HEADER_TRADE_ROLE)
: null;
+ };
final Function> toSecurityDepositColumn = (name) -> isClosedTradeTblBuilder.get()
? new SatoshiColumn(name)
@@ -161,21 +170,42 @@ public TradeTableColumnSupplier(TableType tableType, List trades) {
private final Function> toBooleanColumn = BooleanColumn::new;
- final Supplier> depositPublishedColumn = () -> isTradeDetailTblBuilder.get()
- ? toBooleanColumn.apply(COL_HEADER_TRADE_DEPOSIT_PUBLISHED)
- : null;
+ final Supplier> depositPublishedColumn = () -> {
+ if (isSwapTradeDetail.get())
+ return null;
+ else
+ return isTradeDetailTblBuilder.get()
+ ? toBooleanColumn.apply(COL_HEADER_TRADE_DEPOSIT_PUBLISHED)
+ : null;
+ };
- final Supplier> depositConfirmedColumn = () -> isTradeDetailTblBuilder.get()
- ? toBooleanColumn.apply(COL_HEADER_TRADE_DEPOSIT_CONFIRMED)
- : null;
+ final Supplier> depositConfirmedColumn = () -> {
+ if (isSwapTradeDetail.get())
+ return null;
+ else
+ return isTradeDetailTblBuilder.get()
+ ? toBooleanColumn.apply(COL_HEADER_TRADE_DEPOSIT_CONFIRMED)
+ : null;
- final Supplier> payoutPublishedColumn = () -> isTradeDetailTblBuilder.get()
- ? toBooleanColumn.apply(COL_HEADER_TRADE_PAYOUT_PUBLISHED)
- : null;
+ };
- final Supplier> fundsWithdrawnColumn = () -> isTradeDetailTblBuilder.get()
- ? toBooleanColumn.apply(COL_HEADER_TRADE_WITHDRAWN)
- : null;
+ final Supplier> payoutPublishedColumn = () -> {
+ if (isSwapTradeDetail.get())
+ return null;
+ else
+ return isTradeDetailTblBuilder.get()
+ ? toBooleanColumn.apply(COL_HEADER_TRADE_PAYOUT_PUBLISHED)
+ : null;
+ };
+
+ final Supplier> fundsWithdrawnColumn = () -> {
+ if (isSwapTradeDetail.get())
+ return null;
+ else
+ return isTradeDetailTblBuilder.get()
+ ? toBooleanColumn.apply(COL_HEADER_TRADE_WITHDRAWN)
+ : null;
+ };
final Supplier> bisqTradeDetailFeeColumn = () -> {
if (isTradeDetailTblBuilder.get()) {
@@ -184,8 +214,8 @@ public TradeTableColumnSupplier(TableType tableType, List trades) {
? t.getIsCurrencyForTakerFeeBtc() ? "BTC" : "BSQ"
: t.getOffer().getIsCurrencyForMakerFeeBtc() ? "BTC" : "BSQ";
String colHeader = isTaker.test(t)
- ? String.format(COL_HEADER_TRADE_TAKER_FEE, headerCurrencyCode)
- : String.format(COL_HEADER_TRADE_MAKER_FEE, headerCurrencyCode);
+ ? format(COL_HEADER_TRADE_TAKER_FEE, headerCurrencyCode)
+ : format(COL_HEADER_TRADE_MAKER_FEE, headerCurrencyCode);
boolean isBsqSatoshis = headerCurrencyCode.equals("BSQ");
return new SatoshiColumn(colHeader, isBsqSatoshis);
} else {
@@ -201,7 +231,7 @@ public TradeTableColumnSupplier(TableType tableType, List trades) {
final Supplier> paymentSentColumn = () -> {
if (isTradeDetailTblBuilder.get()) {
String headerCurrencyCode = toPaymentCurrencyCode.apply(firstRow.get());
- String colHeader = String.format(COL_HEADER_TRADE_PAYMENT_SENT, headerCurrencyCode);
+ String colHeader = format(COL_HEADER_TRADE_PAYMENT_SENT, headerCurrencyCode);
return new BooleanColumn(colHeader);
} else {
return null;
@@ -211,7 +241,7 @@ public TradeTableColumnSupplier(TableType tableType, List trades) {
final Supplier> paymentReceivedColumn = () -> {
if (isTradeDetailTblBuilder.get()) {
String headerCurrencyCode = toPaymentCurrencyCode.apply(firstRow.get());
- String colHeader = String.format(COL_HEADER_TRADE_PAYMENT_RECEIVED, headerCurrencyCode);
+ String colHeader = format(COL_HEADER_TRADE_PAYMENT_RECEIVED, headerCurrencyCode);
return new BooleanColumn(colHeader);
} else {
return null;
@@ -222,7 +252,7 @@ public TradeTableColumnSupplier(TableType tableType, List trades) {
if (isTradeDetailTblBuilder.get()) {
TradeInfo t = firstRow.get();
String headerCurrencyCode = t.getOffer().getCounterCurrencyCode();
- String colHeader = String.format(COL_HEADER_TRADE_BUYER_COST, headerCurrencyCode);
+ String colHeader = format(COL_HEADER_TRADE_BUYER_COST, headerCurrencyCode);
return isFiatTrade.test(t)
? new FiatColumn(colHeader, VOLUME)
: new SatoshiColumn(colHeader);
@@ -231,6 +261,18 @@ public TradeTableColumnSupplier(TableType tableType, List trades) {
}
};
+ final Supplier> bsqSwapTxIdColumn = () -> isSwapTradeDetail.get()
+ ? new StringColumn(COL_HEADER_TX_ID)
+ : null;
+
+ final Supplier> bsqSwapStatusColumn = () -> isSwapTradeDetail.get()
+ ? new StringColumn(COL_HEADER_STATUS)
+ : null;
+
+ final Supplier> numConfirmationsColumn = () -> isSwapTradeDetail.get()
+ ? new LongColumn(COL_HEADER_CONFIRMATIONS)
+ : null;
+
final Predicate showAltCoinBuyerAddress = (t) -> {
if (isFiatTrade.test(t)) {
return false;
@@ -251,7 +293,7 @@ public TradeTableColumnSupplier(TableType tableType, List trades) {
TradeInfo t = firstRow.get();
if (showAltCoinBuyerAddress.test(t)) {
String headerCurrencyCode = toPaymentCurrencyCode.apply(t);
- String colHeader = String.format(COL_HEADER_TRADE_ALTCOIN_BUYER_ADDRESS, headerCurrencyCode);
+ String colHeader = format(COL_HEADER_TRADE_ALTCOIN_BUYER_ADDRESS, headerCurrencyCode);
return new StringColumn(colHeader);
} else {
return null;
diff --git a/cli/src/main/java/bisq/cli/table/column/IntegerColumn.java b/cli/src/main/java/bisq/cli/table/column/IntegerColumn.java
new file mode 100644
index 00000000000..5c4e04af9d0
--- /dev/null
+++ b/cli/src/main/java/bisq/cli/table/column/IntegerColumn.java
@@ -0,0 +1,93 @@
+/*
+ * 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 .
+ */
+
+package bisq.cli.table.column;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.stream.IntStream;
+
+import static bisq.cli.table.column.Column.JUSTIFICATION.RIGHT;
+
+/**
+ * For displaying Integer values.
+ */
+public class IntegerColumn extends NumberColumn {
+
+ protected final List rows = new ArrayList<>();
+
+ protected final Predicate isNewMaxWidth = (s) -> s != null && !s.isEmpty() && s.length() > maxWidth;
+
+ // The default IntegerColumn JUSTIFICATION is RIGHT.
+ public IntegerColumn(String name) {
+ this(name, RIGHT);
+ }
+
+ public IntegerColumn(String name, JUSTIFICATION justification) {
+ super(name, justification);
+ this.maxWidth = name.length();
+ }
+
+ @Override
+ public void addRow(Integer value) {
+ rows.add(value);
+
+ String s = String.valueOf(value);
+ if (isNewMaxWidth.test(s))
+ maxWidth = s.length();
+ }
+
+ @Override
+ public List getRows() {
+ return rows;
+ }
+
+ @Override
+ public int rowCount() {
+ return rows.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return rows.isEmpty();
+ }
+
+ @Override
+ public Integer getRow(int rowIndex) {
+ return rows.get(rowIndex);
+ }
+
+ @Override
+ public void updateRow(int rowIndex, Integer newValue) {
+ rows.set(rowIndex, newValue);
+ }
+
+ @Override
+ public String getRowAsFormattedString(int rowIndex) {
+ String s = String.valueOf(getRow(rowIndex));
+ return toJustifiedString(s);
+ }
+
+ @Override
+ public StringColumn asStringColumn() {
+ IntStream.range(0, rows.size()).forEachOrdered(rowIndex ->
+ stringColumn.addRow(getRowAsFormattedString(rowIndex)));
+
+ return stringColumn;
+ }
+}
diff --git a/cli/src/test/java/bisq/cli/CreateOfferSmokeTest.java b/cli/src/test/java/bisq/cli/CreateOfferSmokeTest.java
new file mode 100644
index 00000000000..0cb717f935e
--- /dev/null
+++ b/cli/src/test/java/bisq/cli/CreateOfferSmokeTest.java
@@ -0,0 +1,85 @@
+package bisq.cli;
+
+import static java.lang.System.out;
+import static java.util.Arrays.stream;
+
+/**
+ Smoke tests for createoffer method. Useful for testing CLI command and examining the
+ format of its console output.
+
+ Prerequisites:
+
+ - Run `./bisq-apitest --apiPassword=xyz --supportingApps=bitcoind,seednode,arbdaemon,alicedaemon,bobdaemon --shutdownAfterTests=false --enableBisqDebugging=false`
+
+ Note: Test harness will not automatically generate BTC blocks to confirm transactions.
+
+ Never run on mainnet!
+ */
+@SuppressWarnings({"CommentedOutCode", "unused"})
+public class CreateOfferSmokeTest extends AbstractCliTest {
+
+ public static void main(String[] args) {
+ createBsqSwapOffer("buy");
+ createBsqSwapOffer("sell");
+ }
+
+ private static void createBsqSwapOffer(String direction) {
+ String[] args = createBsqSwapOfferCommand(direction, "0.01", "0.005", "0.00005");
+ out.print(">>>>> bisq-cli ");
+ stream(args).forEach(a -> out.print(a + " "));
+ out.println();
+ CliMain.main(args);
+ out.println("<<<<<");
+
+ args = getMyOffersCommand(direction);
+ out.print(">>>>> bisq-cli ");
+ stream(args).forEach(a -> out.print(a + " "));
+ out.println();
+ CliMain.main(args);
+ out.println("<<<<<");
+
+ args = getAvailableOffersCommand(direction);
+ out.print(">>>>> bisq-cli ");
+ stream(args).forEach(a -> out.print(a + " "));
+ out.println();
+ CliMain.main(args);
+ out.println("<<<<<");
+ }
+
+ private static String[] createBsqSwapOfferCommand(String direction,
+ String amount,
+ String minAmount,
+ String fixedPrice) {
+ return new String[]{
+ PASSWORD_OPT,
+ ALICE_PORT_OPT,
+ "createoffer",
+ "--swap=true",
+ "--direction=" + direction,
+ "--currency-code=bsq",
+ "--amount=" + amount,
+ "--min-amount=" + minAmount,
+ "--fixed-price=" + fixedPrice
+ };
+ }
+
+ private static String[] getMyOffersCommand(String direction) {
+ return new String[]{
+ PASSWORD_OPT,
+ ALICE_PORT_OPT,
+ "getmyoffers",
+ "--direction=" + direction,
+ "--currency-code=bsq"
+ };
+ }
+
+ private static String[] getAvailableOffersCommand(String direction) {
+ return new String[]{
+ PASSWORD_OPT,
+ BOB_PORT_OPT,
+ "getoffers",
+ "--direction=" + direction,
+ "--currency-code=bsq"
+ };
+ }
+}
diff --git a/cli/src/test/java/bisq/cli/GetOffersSmokeTest.java b/cli/src/test/java/bisq/cli/GetOffersSmokeTest.java
index f613aea358c..fc6ee7b4dbd 100644
--- a/cli/src/test/java/bisq/cli/GetOffersSmokeTest.java
+++ b/cli/src/test/java/bisq/cli/GetOffersSmokeTest.java
@@ -11,15 +11,50 @@
This can be run on mainnet.
*/
-public class GetOffersSmokeTest {
+@SuppressWarnings({"CommentedOutCode", "unused"})
+public class GetOffersSmokeTest extends AbstractCliTest {
+
+ // TODO use the static password and port opt definitions in superclass
public static void main(String[] args) {
+ getMyBsqOffers();
+ // getAvailableBsqOffers();
+ // getMyUsdOffers();
+ // getAvailableUsdOffers();
+ }
+
+ private static void getMyBsqOffers() {
+ out.println(">>> getmyoffers buy bsq");
+ CliMain.main(new String[]{"--password=xyz", "--port=9998", "getmyoffers", "--direction=buy", "--currency-code=bsq"});
+ out.println(">>> getmyoffers sell bsq");
+ CliMain.main(new String[]{"--password=xyz", "--port=9998", "getmyoffers", "--direction=sell", "--currency-code=bsq"});
+ out.println(">>> getmyoffer --offer-id=KRONTTMO-11cef1a9-c636-4dc7-b3f2-1616e4960c28-175");
+ CliMain.main(new String[]{"--password=xyz", "--port=9998", "getmyoffer", "--offer-id=KRONTTMO-11cef1a9-c636-4dc7-b3f2-1616e4960c28-175"});
+ }
+
+ private static void getAvailableBsqOffers() {
+ out.println(">>> getoffers buy bsq");
+ CliMain.main(new String[]{"--password=xyz", "--port=9998", "getoffers", "--direction=buy", "--currency-code=bsq"});
+ out.println(">>> getoffers sell bsq");
+ CliMain.main(new String[]{"--password=xyz", "--port=9998", "getoffers", "--direction=sell", "--currency-code=bsq"});
+ }
+
+ private static void getMyUsdOffers() {
+ out.println(">>> getmyoffers buy usd");
+ CliMain.main(new String[]{"--password=xyz", "--port=9998", "getmyoffers", "--direction=buy", "--currency-code=usd"});
+ out.println(">>> getmyoffers sell usd");
+ CliMain.main(new String[]{"--password=xyz", "--port=9998", "getmyoffers", "--direction=sell", "--currency-code=usd"});
+ }
+
+ private static void getAvailableUsdOffers() {
out.println(">>> getoffers buy usd");
- CliMain.main(new String[]{"--password=xyz", "getoffers", "--direction=buy", "--currency-code=usd"});
+ CliMain.main(new String[]{"--password=xyz", "--port=9998", "getoffers", "--direction=buy", "--currency-code=usd"});
out.println(">>> getoffers sell usd");
- CliMain.main(new String[]{"--password=xyz", "getoffers", "--direction=sell", "--currency-code=usd"});
+ CliMain.main(new String[]{"--password=xyz", "--port=9998", "getoffers", "--direction=sell", "--currency-code=usd"});
+ }
+ private static void TODO() {
out.println(">>> getoffers buy eur");
CliMain.main(new String[]{"--password=xyz", "getoffers", "--direction=buy", "--currency-code=eur"});
out.println(">>> getoffers sell eur");
@@ -35,5 +70,4 @@ public static void main(String[] args) {
out.println(">>> getoffers sell brl");
CliMain.main(new String[]{"--password=xyz", "getoffers", "--direction=sell", "--currency-code=brl"});
}
-
}
diff --git a/cli/src/test/java/bisq/cli/opts/OptionParsersTest.java b/cli/src/test/java/bisq/cli/opts/OptionParsersTest.java
index 58b8712fe90..ba527a88e5a 100644
--- a/cli/src/test/java/bisq/cli/opts/OptionParsersTest.java
+++ b/cli/src/test/java/bisq/cli/opts/OptionParsersTest.java
@@ -9,6 +9,7 @@
import static bisq.cli.opts.OptLabel.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
public class OptionParsersTest {
@@ -62,13 +63,16 @@ public void testValidCancelOfferOpts() {
new CancelOfferOptionParser(args).parse();
}
- // createoffer opt parser tests
+ // createoffer (v1) opt parser tests
@Test
- public void testCreateOfferOptParserWithMissingPaymentAccountIdOptShouldThrowException() {
+ public void testCreateOfferWithMissingPaymentAccountIdOptShouldThrowException() {
String[] args = new String[]{
PASSWORD_OPT,
- createoffer.name()
+ createoffer.name(),
+ "--" + OPT_DIRECTION + "=" + "SELL",
+ "--" + OPT_CURRENCY_CODE + "=" + "JPY",
+ "--" + OPT_AMOUNT + "=" + "0.1"
};
Throwable exception = assertThrows(RuntimeException.class, () ->
new CreateOfferOptionParser(args).parse());
@@ -76,7 +80,7 @@ public void testCreateOfferOptParserWithMissingPaymentAccountIdOptShouldThrowExc
}
@Test
- public void testCreateOfferOptParserWithEmptyPaymentAccountIdOptShouldThrowException() {
+ public void testCreateOfferWithEmptyPaymentAccountIdOptShouldThrowException() {
String[] args = new String[]{
PASSWORD_OPT,
createoffer.name(),
@@ -88,7 +92,7 @@ public void testCreateOfferOptParserWithEmptyPaymentAccountIdOptShouldThrowExcep
}
@Test
- public void testCreateOfferOptParserWithMissingDirectionOptShouldThrowException() {
+ public void testCreateOfferWithMissingDirectionOptShouldThrowException() {
String[] args = new String[]{
PASSWORD_OPT,
createoffer.name(),
@@ -101,7 +105,7 @@ public void testCreateOfferOptParserWithMissingDirectionOptShouldThrowException(
@Test
- public void testCreateOfferOptParserWithMissingDirectionOptValueShouldThrowException() {
+ public void testCreateOfferWithMissingDirectionOptValueShouldThrowException() {
String[] args = new String[]{
PASSWORD_OPT,
createoffer.name(),
@@ -134,10 +138,114 @@ public void testValidCreateOfferOpts() {
assertEquals("25.0", parser.getSecurityDeposit());
}
+ // createoffer (bsq swap) opt parser tests
+
+ @Test
+ public void testCreateBsqSwapOfferWithPaymentAcctIdOptShouldThrowException() {
+ String[] args = new String[]{
+ PASSWORD_OPT,
+ createoffer.name(),
+ "--" + OPT_SWAP + "=" + "true",
+ "--" + OPT_PAYMENT_ACCOUNT + "=" + "abc",
+ "--" + OPT_DIRECTION + "=" + "buy",
+ "--" + OPT_CURRENCY_CODE + "=" + "bsq",
+ "--" + OPT_AMOUNT + "=" + "0.125"
+ };
+ Throwable exception = assertThrows(RuntimeException.class, () ->
+ new CreateOfferOptionParser(args).parse());
+ assertEquals("cannot use a payment account id in bsq swap offer", exception.getMessage());
+ }
+
+ @Test
+ public void testCreateBsqSwapOfferWithMktMarginPriceOptShouldThrowException() {
+ String[] args = new String[]{
+ PASSWORD_OPT,
+ createoffer.name(),
+ "--" + OPT_SWAP + "=" + "true",
+ "--" + OPT_DIRECTION + "=" + "buy",
+ "--" + OPT_CURRENCY_CODE + "=" + "bsq",
+ "--" + OPT_AMOUNT + "=" + "0.125",
+ "--" + OPT_MKT_PRICE_MARGIN + "=" + "0.0"
+ };
+ Throwable exception = assertThrows(RuntimeException.class, () ->
+ new CreateOfferOptionParser(args).parse());
+ assertEquals("cannot use a market price margin in bsq swap offer", exception.getMessage());
+ }
+
+ @Test
+ public void testCreateBsqSwapOfferWithSecurityDepositOptShouldThrowException() {
+ String[] args = new String[]{
+ PASSWORD_OPT,
+ createoffer.name(),
+ "--" + OPT_SWAP + "=" + "true",
+ "--" + OPT_DIRECTION + "=" + "buy",
+ "--" + OPT_CURRENCY_CODE + "=" + "bsq",
+ "--" + OPT_AMOUNT + "=" + "0.125",
+ "--" + OPT_SECURITY_DEPOSIT + "=" + "25.0"
+ };
+ Throwable exception = assertThrows(RuntimeException.class, () ->
+ new CreateOfferOptionParser(args).parse());
+ assertEquals("cannot use a security deposit in bsq swap offer", exception.getMessage());
+ }
+
+ @Test
+ public void testCreateBsqSwapOfferWithMissingFixedPriceOptShouldThrowException() {
+ String[] args = new String[]{
+ PASSWORD_OPT,
+ createoffer.name(),
+ "--" + OPT_SWAP + "=" + "true",
+ "--" + OPT_DIRECTION + "=" + "sell",
+ "--" + OPT_CURRENCY_CODE + "=" + "bsq",
+ "--" + OPT_MIN_AMOUNT + "=" + "0.075",
+ "--" + OPT_AMOUNT + "=" + "0.125"
+ };
+ Throwable exception = assertThrows(RuntimeException.class, () ->
+ new CreateOfferOptionParser(args).parse());
+ assertEquals("no fixed price specified", exception.getMessage());
+ }
+
+ @Test
+ public void testCreateBsqSwapOfferWithIncorrectCurrencyCodeOptShouldThrowException() {
+ String[] args = new String[]{
+ PASSWORD_OPT,
+ createoffer.name(),
+ "--" + OPT_SWAP + "=" + "true",
+ "--" + OPT_DIRECTION + "=" + "sell",
+ "--" + OPT_CURRENCY_CODE + "=" + "xmr",
+ "--" + OPT_MIN_AMOUNT + "=" + "0.075",
+ "--" + OPT_AMOUNT + "=" + "0.125",
+ "--" + OPT_FIXED_PRICE + "=" + "0.00005555"
+ };
+ Throwable exception = assertThrows(RuntimeException.class, () ->
+ new CreateOfferOptionParser(args).parse());
+ assertEquals("only bsq swaps are currently supported", exception.getMessage());
+ }
+
+ @Test
+ public void testValidCreateBsqSwapOfferOpts() {
+ String[] args = new String[]{
+ PASSWORD_OPT,
+ createoffer.name(),
+ "--" + OPT_SWAP + "=" + "true",
+ "--" + OPT_DIRECTION + "=" + "sell",
+ "--" + OPT_CURRENCY_CODE + "=" + "bsq",
+ "--" + OPT_MIN_AMOUNT + "=" + "0.075",
+ "--" + OPT_AMOUNT + "=" + "0.125",
+ "--" + OPT_FIXED_PRICE + "=" + "0.00005555"
+ };
+ CreateOfferOptionParser parser = new CreateOfferOptionParser(args).parse();
+ assertTrue(parser.getIsSwap());
+ assertEquals("sell", parser.getDirection());
+ assertEquals("bsq", parser.getCurrencyCode());
+ assertEquals("0.075", parser.getMinAmount());
+ assertEquals("0.125", parser.getAmount());
+ assertEquals("0.00005555", parser.getFixedPrice());
+ }
+
// createpaymentacct opt parser tests
@Test
- public void testCreatePaymentAcctOptParserWithMissingPaymentFormOptShouldThrowException() {
+ public void testCreatePaymentAcctWithMissingPaymentFormOptShouldThrowException() {
String[] args = new String[]{
PASSWORD_OPT,
createpaymentacct.name()
@@ -149,7 +257,7 @@ public void testCreatePaymentAcctOptParserWithMissingPaymentFormOptShouldThrowEx
}
@Test
- public void testCreatePaymentAcctOptParserWithMissingPaymentFormOptValueShouldThrowException() {
+ public void testCreatePaymentAcctWithMissingPaymentFormOptValueShouldThrowException() {
String[] args = new String[]{
PASSWORD_OPT,
createpaymentacct.name(),
@@ -161,7 +269,7 @@ public void testCreatePaymentAcctOptParserWithMissingPaymentFormOptValueShouldTh
}
@Test
- public void testCreatePaymentAcctOptParserWithInvalidPaymentFormOptValueShouldThrowException() {
+ public void testCreatePaymentAcctWithInvalidPaymentFormOptValueShouldThrowException() {
String[] args = new String[]{
PASSWORD_OPT,
createpaymentacct.name(),
@@ -180,7 +288,7 @@ public void testCreatePaymentAcctOptParserWithInvalidPaymentFormOptValueShouldTh
// createcryptopaymentacct parser tests
@Test
- public void testCreateCryptoCurrencyPaymentAcctOptionParserWithMissingAcctNameOptShouldThrowException() {
+ public void testCreateCryptoCurrencyPaymentAcctWithMissingAcctNameOptShouldThrowException() {
String[] args = new String[]{
PASSWORD_OPT,
createcryptopaymentacct.name()
@@ -191,7 +299,7 @@ public void testCreateCryptoCurrencyPaymentAcctOptionParserWithMissingAcctNameOp
}
@Test
- public void testCreateCryptoCurrencyPaymentAcctOptionParserWithEmptyAcctNameOptShouldThrowException() {
+ public void testCreateCryptoCurrencyPaymentAcctWithEmptyAcctNameOptShouldThrowException() {
String[] args = new String[]{
PASSWORD_OPT,
createcryptopaymentacct.name(),
@@ -203,7 +311,7 @@ public void testCreateCryptoCurrencyPaymentAcctOptionParserWithEmptyAcctNameOptS
}
@Test
- public void testCreateCryptoCurrencyPaymentAcctOptionParserWithMissingCurrencyCodeOptShouldThrowException() {
+ public void testCreateCryptoCurrencyPaymentAcctWithMissingCurrencyCodeOptShouldThrowException() {
String[] args = new String[]{
PASSWORD_OPT,
createcryptopaymentacct.name(),
@@ -215,7 +323,7 @@ public void testCreateCryptoCurrencyPaymentAcctOptionParserWithMissingCurrencyCo
}
@Test
- public void testCreateCryptoCurrencyPaymentAcctOptionParserWithInvalidCurrencyCodeOptShouldThrowException() {
+ public void testCreateCryptoCurrencyPaymentAcctWithInvalidCurrencyCodeOptShouldThrowException() {
String[] args = new String[]{
PASSWORD_OPT,
createcryptopaymentacct.name(),
@@ -228,7 +336,7 @@ public void testCreateCryptoCurrencyPaymentAcctOptionParserWithInvalidCurrencyCo
}
@Test
- public void testCreateCryptoCurrencyPaymentAcctOptionParserWithMissingAddressOptShouldThrowException() {
+ public void testCreateCryptoCurrencyPaymentAcctWithMissingAddressOptShouldThrowException() {
String[] args = new String[]{
PASSWORD_OPT,
createcryptopaymentacct.name(),
@@ -241,7 +349,7 @@ public void testCreateCryptoCurrencyPaymentAcctOptionParserWithMissingAddressOpt
}
@Test
- public void testCreateCryptoCurrencyPaymentAcctOptionParser() {
+ public void testCreateCryptoCurrencyPaymentAcct() {
var acctName = "bsq payment account";
var currencyCode = "bsq";
var address = "B1nXyZ"; // address is validated on server
diff --git a/core/src/main/java/bisq/core/api/CoreApi.java b/core/src/main/java/bisq/core/api/CoreApi.java
index 510c4cfcbc7..caa9e2650a6 100644
--- a/core/src/main/java/bisq/core/api/CoreApi.java
+++ b/core/src/main/java/bisq/core/api/CoreApi.java
@@ -26,6 +26,7 @@
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.PaymentMethod;
import bisq.core.trade.bisq_v1.TradeResultHandler;
+import bisq.core.trade.model.TradeModel;
import bisq.core.trade.model.bisq_v1.Trade;
import bisq.core.trade.model.bsq_swap.BsqSwapTrade;
import bisq.core.trade.statistics.TradeStatistics3;
@@ -119,6 +120,18 @@ public String getMethodHelp(String methodName) {
// Offers
///////////////////////////////////////////////////////////////////////////////////////////
+ public boolean isFiatOffer(String id, boolean isMyOffer) {
+ return coreOffersService.isFiatOffer(id, isMyOffer);
+ }
+
+ public boolean isAltcoinOffer(String id, boolean isMyOffer) {
+ return coreOffersService.isAltcoinOffer(id, isMyOffer);
+ }
+
+ public boolean isBsqSwapOffer(String id, boolean isMyOffer) {
+ return coreOffersService.isBsqSwapOffer(id, isMyOffer);
+ }
+
public Offer getBsqSwapOffer(String id) {
return coreOffersService.getBsqSwapOffer(id);
}
@@ -264,14 +277,10 @@ public void getMarketPrice(String currencyCode, Consumer resultHandler)
///////////////////////////////////////////////////////////////////////////////////////////
public void takeBsqSwapOffer(String offerId,
- String paymentAccountId,
- String takerFeeCurrencyCode,
TradeResultHandler tradeResultHandler,
ErrorMessageHandler errorMessageHandler) {
Offer bsqSwapOffer = coreOffersService.getBsqSwapOffer(offerId);
coreTradesService.takeBsqSwapOffer(bsqSwapOffer,
- paymentAccountId,
- takerFeeCurrencyCode,
tradeResultHandler,
errorMessageHandler);
}
@@ -305,18 +314,18 @@ public void withdrawFunds(String tradeId, String address, String memo) {
coreTradesService.withdrawFunds(tradeId, address, memo);
}
- public BsqSwapTrade getBsqSwapTrade(String tradeId) {
- return coreTradesService.getBsqSwapTrade(tradeId);
- }
-
- public Trade getTrade(String tradeId) {
- return coreTradesService.getTrade(tradeId);
+ public TradeModel getTradeModel(String tradeId) {
+ return coreTradesService.getTradeModel(tradeId);
}
public String getTradeRole(String tradeId) {
return coreTradesService.getTradeRole(tradeId);
}
+ public String getBsqSwapTradeRole(BsqSwapTrade bsqSwapTrade) {
+ return coreTradesService.getBsqSwapTradeRole(bsqSwapTrade);
+ }
+
///////////////////////////////////////////////////////////////////////////////////////////
// Wallets
///////////////////////////////////////////////////////////////////////////////////////////
@@ -381,6 +390,10 @@ public Transaction getTransaction(String txId) {
return walletsService.getTransaction(txId);
}
+ public int getTransactionConfirmations(String txId) {
+ return walletsService.getTransactionConfirmations(txId);
+ }
+
public void setWalletPassword(String password, String newPassword) {
walletsService.setWalletPassword(password, newPassword);
}
diff --git a/core/src/main/java/bisq/core/api/CoreOffersService.java b/core/src/main/java/bisq/core/api/CoreOffersService.java
index adbcee01dd4..fde91f273c6 100644
--- a/core/src/main/java/bisq/core/api/CoreOffersService.java
+++ b/core/src/main/java/bisq/core/api/CoreOffersService.java
@@ -48,6 +48,8 @@
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
+import java.util.Optional;
+import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@@ -60,6 +62,7 @@
import static bisq.core.locale.CurrencyUtil.isCryptoCurrency;
import static bisq.core.offer.Offer.State;
import static bisq.core.offer.OfferDirection.BUY;
+import static bisq.core.offer.OfferUtil.getRandomOfferId;
import static bisq.core.offer.OpenOffer.State.AVAILABLE;
import static bisq.core.offer.OpenOffer.State.DEACTIVATED;
import static bisq.core.payment.PaymentAccountUtil.isPaymentAccountValidForOffer;
@@ -78,6 +81,9 @@ class CoreOffersService {
private final Supplier> openOfferPriceComparator = () ->
comparing(openOffer -> openOffer.getOffer().getPrice());
+ private final BiFunction toOfferWithId = (id, isMyOffer) ->
+ isMyOffer ? getMyOffer(id).getOffer() : getOffer(id);
+
private final CoreContext coreContext;
private final KeyRing keyRing;
// Dependencies on core api services in this package must be kept to an absolute
@@ -118,51 +124,48 @@ public CoreOffersService(CoreContext coreContext,
this.user = user;
}
- Offer getBsqSwapOffer(String id) {
- return offerBookService.getOffers().stream()
- .filter(o -> o.getId().equals(id))
- .filter(o -> !o.isMyOffer(keyRing))
- .filter(o -> offerFilterService.canTakeOffer(o, coreContext.isApiUser()).isValid())
- .filter(o -> o.isBsqSwapOffer())
- .findAny().orElseThrow(() ->
- new IllegalStateException(format("offer with id '%s' not found", id)));
+ boolean isFiatOffer(String id, boolean isMyOffer) {
+ var offer = toOfferWithId.apply(id, isMyOffer);
+ return OfferUtil.isFiatOffer(offer);
+ }
+
+ boolean isAltcoinOffer(String id, boolean isMyOffer) {
+ var offer = toOfferWithId.apply(id, isMyOffer);
+ return OfferUtil.isAltcoinOffer(offer);
+ }
+
+ boolean isBsqSwapOffer(String id, boolean isMyOffer) {
+ var offer = toOfferWithId.apply(id, isMyOffer);
+ return offer.isBsqSwapOffer();
}
Offer getOffer(String id) {
- return offerBookService.getOffers().stream()
- .filter(o -> o.getId().equals(id))
- .filter(o -> !o.isMyOffer(keyRing))
- .filter(o -> offerFilterService.canTakeOffer(o, coreContext.isApiUser()).isValid())
- .findAny().orElseThrow(() ->
- new IllegalStateException(format("offer with id '%s' not found", id)));
+ return findAvailableOffer(id).orElseThrow(() ->
+ new IllegalStateException(format("offer with id '%s' not found", id)));
}
OpenOffer getMyOffer(String id) {
- return openOfferManager.getObservableList().stream()
- .filter(o -> o.getId().equals(id))
- .filter(o -> o.getOffer().isMyOffer(keyRing))
- .findAny().orElseThrow(() ->
- new IllegalStateException(format("offer with id '%s' not found", id)));
+ return findMyOpenOffer(id).orElseThrow(() ->
+ new IllegalStateException(format("offer with id '%s' not found", id)));
}
- Offer getMyBsqSwapOffer(String id) {
- return offerBookService.getOffers().stream()
- .filter(o -> o.getId().equals(id))
- .filter(o -> o.isMyOffer(keyRing))
- .filter(o -> o.isBsqSwapOffer())
- .findAny().orElseThrow(() ->
- new IllegalStateException(format("offer with id '%s' not found", id)));
+ Offer getBsqSwapOffer(String id) {
+ return findAvailableBsqSwapOffer(id).orElseThrow(() ->
+ new IllegalStateException(format("offer with id '%s' not found", id)));
}
+ Offer getMyBsqSwapOffer(String id) {
+ return findMyBsqSwapOffer(id).orElseThrow(() ->
+ new IllegalStateException(format("offer with id '%s' not found", id)));
+ }
List getBsqSwapOffers(String direction) {
- var offers = offerBookService.getOffers().stream()
+ return offerBookService.getOffers().stream()
.filter(o -> !o.isMyOffer(keyRing))
.filter(o -> o.getDirection().name().equalsIgnoreCase(direction))
- .filter(o -> o.isBsqSwapOffer())
+ .filter(Offer::isBsqSwapOffer)
.sorted(priceComparator(direction))
.collect(Collectors.toList());
- return offers;
}
List getOffers(String direction, String currencyCode) {
@@ -183,13 +186,12 @@ List getMyOffers(String direction, String currencyCode) {
}
List getMyBsqSwapOffers(String direction) {
- var offers = offerBookService.getOffers().stream()
+ return offerBookService.getOffers().stream()
.filter(o -> o.isMyOffer(keyRing))
.filter(o -> o.getDirection().name().equalsIgnoreCase(direction))
.filter(Offer::isBsqSwapOffer)
.sorted(priceComparator(direction))
.collect(Collectors.toList());
- return offers;
}
OpenOffer getMyOpenBsqSwapOffer(String id) {
@@ -208,9 +210,12 @@ OpenOffer getMyOpenOffer(String id) {
}
boolean isMyOffer(String id) {
- return openOfferManager.getOpenOfferById(id)
+ boolean isMyOpenOffer = openOfferManager.getOpenOfferById(id)
.filter(open -> open.getOffer().isMyOffer(keyRing))
.isPresent();
+ boolean wasMyOffer = offerBookService.getOffers().stream()
+ .anyMatch(o -> o.getId().equals(id) && o.isMyOffer(keyRing));
+ return isMyOpenOffer || wasMyOffer;
}
void createAndPlaceBsqSwapOffer(String directionAsString,
@@ -222,7 +227,7 @@ void createAndPlaceBsqSwapOffer(String directionAsString,
coreWalletsService.verifyEncryptedWalletIsUnlocked();
String currencyCode = "BSQ";
- String offerId = OfferUtil.getRandomOfferId();
+ String offerId = getRandomOfferId();
OfferDirection direction = OfferDirection.valueOf(directionAsString.toUpperCase());
Coin amount = Coin.valueOf(amountAsLong);
Coin minAmount = Coin.valueOf(minAmountAsLong);
@@ -256,7 +261,7 @@ void createAndPlaceOffer(String currencyCode,
throw new IllegalArgumentException(format("payment account with id %s not found", paymentAccountId));
String upperCaseCurrencyCode = currencyCode.toUpperCase();
- String offerId = OfferUtil.getRandomOfferId();
+ String offerId = getRandomOfferId();
OfferDirection direction = OfferDirection.valueOf(directionAsString.toUpperCase());
Price price = Price.valueOf(upperCaseCurrencyCode, priceStringToLong(priceAsString, upperCaseCurrencyCode));
Coin amount = Coin.valueOf(amountAsLong);
@@ -375,6 +380,38 @@ private void placeOffer(Offer offer,
throw new IllegalStateException(offer.getErrorMessage());
}
+ private Optional findAvailableBsqSwapOffer(String id) {
+ return offerBookService.getOffers().stream()
+ .filter(o -> o.getId().equals(id))
+ .filter(o -> !o.isMyOffer(keyRing))
+ .filter(o -> offerFilterService.canTakeOffer(o, coreContext.isApiUser()).isValid())
+ .filter(Offer::isBsqSwapOffer)
+ .findAny();
+ }
+
+ private Optional findMyBsqSwapOffer(String id) {
+ return offerBookService.getOffers().stream()
+ .filter(o -> o.getId().equals(id))
+ .filter(o -> o.isMyOffer(keyRing))
+ .filter(Offer::isBsqSwapOffer)
+ .findAny();
+ }
+
+ private Optional findAvailableOffer(String id) {
+ return offerBookService.getOffers().stream()
+ .filter(o -> o.getId().equals(id))
+ .filter(o -> !o.isMyOffer(keyRing))
+ .filter(o -> offerFilterService.canTakeOffer(o, coreContext.isApiUser()).isValid())
+ .findAny();
+ }
+
+ private Optional findMyOpenOffer(String id) {
+ return openOfferManager.getObservableList().stream()
+ .filter(o -> o.getId().equals(id))
+ .filter(o -> o.getOffer().isMyOffer(keyRing))
+ .findAny();
+ }
+
private OfferPayload getMergedOfferPayload(OpenOffer openOffer,
String editedPriceAsString,
double editedMarketPriceMargin,
@@ -427,10 +464,9 @@ private void verifyPaymentAccountIsValidForNewOffer(Offer offer, PaymentAccount
private boolean offerMatchesDirectionAndCurrency(Offer offer,
String direction,
String currencyCode) {
- var offerOfWantedDirection = offer.getDirection().name().equalsIgnoreCase(direction);
- var offerInWantedCurrency = offer.getCounterCurrencyCode()
- .equalsIgnoreCase(currencyCode);
- return offerOfWantedDirection && offerInWantedCurrency;
+ var isDirectionMatch = offer.getDirection().name().equalsIgnoreCase(direction);
+ var isCurrencyMatch = offer.getCounterCurrencyCode().equalsIgnoreCase(currencyCode);
+ return isDirectionMatch && isCurrencyMatch;
}
private Comparator openOfferPriceComparator(String direction) {
diff --git a/core/src/main/java/bisq/core/api/CoreTradesService.java b/core/src/main/java/bisq/core/api/CoreTradesService.java
index 5c08a61a48f..3184ff31477 100644
--- a/core/src/main/java/bisq/core/api/CoreTradesService.java
+++ b/core/src/main/java/bisq/core/api/CoreTradesService.java
@@ -28,6 +28,7 @@
import bisq.core.trade.bisq_v1.TradeResultHandler;
import bisq.core.trade.bisq_v1.TradeUtil;
import bisq.core.trade.model.Tradable;
+import bisq.core.trade.model.TradeModel;
import bisq.core.trade.model.bisq_v1.Trade;
import bisq.core.trade.model.bsq_swap.BsqSwapTrade;
import bisq.core.trade.protocol.bisq_v1.BuyerProtocol;
@@ -91,27 +92,26 @@ public CoreTradesService(CoreContext coreContext,
this.user = user;
}
- // todo we need to pass the intended trade amount
+ // TODO We need to pass the intended trade amount, not default to the maximum.
void takeBsqSwapOffer(Offer offer,
- String paymentAccountId,
- String takerFeeCurrencyCode,
TradeResultHandler tradeResultHandler,
ErrorMessageHandler errorMessageHandler) {
coreWalletsService.verifyWalletsAreAvailable();
coreWalletsService.verifyEncryptedWalletIsUnlocked();
bsqSwapTakeOfferModel.initWithData(offer);
-
- //todo use the intended trade amount
bsqSwapTakeOfferModel.applyAmount(offer.getAmount());
log.info("Initiating take {} offer, {}",
offer.isBuyOffer() ? "buy" : "sell",
bsqSwapTakeOfferModel);
-
- bsqSwapTakeOfferModel.onTakeOffer(tradeResultHandler, log::warn, errorMessageHandler, coreContext.isApiUser());
+ bsqSwapTakeOfferModel.onTakeOffer(tradeResultHandler,
+ log::warn,
+ errorMessageHandler,
+ coreContext.isApiUser());
}
+ // TODO We need to pass the intended trade amount, not default to the maximum.
void takeOffer(Offer offer,
String paymentAccountId,
String takerFeeCurrencyCode,
@@ -232,13 +232,28 @@ void withdrawFunds(String tradeId, String toAddress, String memo) {
});
}
- BsqSwapTrade getBsqSwapTrade(String tradeId) {
+ TradeModel getTradeModel(String tradeId) {
coreWalletsService.verifyWalletsAreAvailable();
coreWalletsService.verifyEncryptedWalletIsUnlocked();
+
+ Optional openTrade = getOpenTrade(tradeId);
+ if (openTrade.isPresent())
+ return openTrade.get();
+
+ Optional closedTrade = getClosedTrade(tradeId);
+ if (closedTrade.isPresent())
+ return closedTrade.get();
+
return tradeManager.findBsqSwapTradeById(tradeId).orElseThrow(() ->
new IllegalArgumentException(format("trade with id '%s' not found", tradeId)));
}
+ String getBsqSwapTradeRole(BsqSwapTrade bsqSwapTrade) {
+ coreWalletsService.verifyWalletsAreAvailable();
+ coreWalletsService.verifyEncryptedWalletIsUnlocked();
+ return tradeUtil.getRole(bsqSwapTrade);
+ }
+
String getTradeRole(String tradeId) {
coreWalletsService.verifyWalletsAreAvailable();
coreWalletsService.verifyEncryptedWalletIsUnlocked();
diff --git a/core/src/main/java/bisq/core/api/CoreWalletsService.java b/core/src/main/java/bisq/core/api/CoreWalletsService.java
index f2dec09a530..6579786e147 100644
--- a/core/src/main/java/bisq/core/api/CoreWalletsService.java
+++ b/core/src/main/java/bisq/core/api/CoreWalletsService.java
@@ -85,6 +85,7 @@
import static bisq.core.btc.wallet.Restrictions.getMinNonDustOutput;
import static bisq.core.util.ParsingUtils.parseToCoin;
import static java.lang.String.format;
+import static java.util.Objects.requireNonNull;
import static java.util.concurrent.TimeUnit.SECONDS;
@Singleton
@@ -209,10 +210,10 @@ List getFundingAddresses() {
}
return addressStrings.stream().map(address ->
- new AddressBalanceInfo(address,
- balances.getUnchecked(address),
- getNumConfirmationsForMostRecentTransaction(address),
- btcWalletService.isAddressUnused(getAddressEntry(address).getAddress())))
+ new AddressBalanceInfo(address,
+ balances.getUnchecked(address),
+ getNumConfirmationsForMostRecentTransaction(address),
+ btcWalletService.isAddressUnused(getAddressEntry(address).getAddress())))
.collect(Collectors.toList());
}
@@ -324,7 +325,7 @@ boolean verifyBsqSentToAddress(String address, String amount) {
for (TransactionOutput txOut : spendableBsqTxOutputs) {
if (isTxOutputAddressMatch.test(txOut) && isTxOutputValueMatch.test(txOut)) {
log.info("\t\tTx {} output has matching address {} and value {}.",
- txOut.getParentTransaction().getTxId(),
+ requireNonNull(txOut.getParentTransaction()).getTxId(),
address,
txOut.getValue().toPlainString());
numMatches++;
@@ -346,6 +347,7 @@ void getTxFeeRate(ResultHandler resultHandler) {
@SuppressWarnings({"unchecked", "Convert2MethodRef"})
ListenableFuture future =
(ListenableFuture) executor.submit(() -> feeService.requestFees());
+ //noinspection NullableProblems
Futures.addCallback(future, new FutureCallback<>() {
@Override
public void onSuccess(@Nullable Void ignored) {
@@ -393,23 +395,11 @@ TxFeeRateInfo getMostRecentTxFeeRateInfo() {
}
Transaction getTransaction(String txId) {
- if (txId.length() != 64)
- throw new IllegalArgumentException(format("%s is not a transaction id", txId));
-
- try {
- Transaction tx = btcWalletService.getTransaction(txId);
- if (tx == null)
- throw new IllegalArgumentException(format("tx with id %s not found", txId));
- else
- return tx;
+ return getTransactionWithId(txId);
+ }
- } catch (IllegalArgumentException ex) {
- log.error("", ex);
- throw new IllegalArgumentException(
- format("could not get transaction with id %s%ncause: %s",
- txId,
- ex.getMessage().toLowerCase()));
- }
+ int getTransactionConfirmations(String txId) {
+ return getTransactionWithId(txId).getConfidence().getDepthInBlocks();
}
int getNumConfirmationsForMostRecentTransaction(String addressString) {
@@ -654,12 +644,32 @@ private AddressEntry getAddressEntry(String addressString) {
return addressEntry.get();
}
+ private Transaction getTransactionWithId(String txId) {
+ if (txId.length() != 64)
+ throw new IllegalArgumentException(format("%s is not a transaction id", txId));
+
+ try {
+ Transaction tx = btcWalletService.getTransaction(txId);
+ if (tx == null)
+ throw new IllegalArgumentException(format("tx with id %s not found", txId));
+ else
+ return tx;
+
+ } catch (IllegalArgumentException ex) {
+ log.error("", ex);
+ throw new IllegalArgumentException(
+ format("could not get transaction with id %s%ncause: %s",
+ txId,
+ ex.getMessage().toLowerCase()));
+ }
+ }
+
/**
* Memoization stores the results of expensive function calls and returns
* the cached result when the same input occurs again.
*
* Resulting LoadingCache is used by calling `.get(input I)` or
- * `.getUnchecked(input I)`, depending on whether or not `f` can return null.
+ * `.getUnchecked(input I)`, depending on whether `f` can return null.
* That's because CacheLoader throws an exception on null output from `f`.
*/
private static LoadingCache memoize(Function f) {
diff --git a/core/src/main/java/bisq/core/api/EditOfferValidator.java b/core/src/main/java/bisq/core/api/EditOfferValidator.java
index 7a9840c3cdb..89c9366e1eb 100644
--- a/core/src/main/java/bisq/core/api/EditOfferValidator.java
+++ b/core/src/main/java/bisq/core/api/EditOfferValidator.java
@@ -45,7 +45,8 @@ class EditOfferValidator {
}
void validate() {
- log.info("Verifying 'editoffer' params OK for editType {}", editType);
+ log.info("Verifying 'editoffer' params for editType {}", editType);
+ checkNotBsqSwapOffer();
switch (editType) {
case ACTIVATION_STATE_ONLY: {
validateEditedActivationState();
@@ -138,4 +139,11 @@ private void checkNotAltcoinOffer() {
currentlyOpenOffer.getId()));
}
}
+
+ private void checkNotBsqSwapOffer() {
+ if (currentlyOpenOffer.getOffer().isBsqSwapOffer()) {
+ throw new IllegalStateException(
+ format("cannot edit bsq swap offer with id '%s'", currentlyOpenOffer.getId()));
+ }
+ }
}
diff --git a/core/src/main/java/bisq/core/api/model/BsqSwapOfferInfo.java b/core/src/main/java/bisq/core/api/model/BsqSwapOfferInfo.java
deleted file mode 100644
index 487e4fbf23f..00000000000
--- a/core/src/main/java/bisq/core/api/model/BsqSwapOfferInfo.java
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * 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 .
- */
-
-package bisq.core.api.model;
-
-import bisq.core.offer.Offer;
-
-import bisq.common.Payload;
-
-import java.util.Objects;
-
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.ToString;
-
-@EqualsAndHashCode
-@ToString
-@Getter
-public class BsqSwapOfferInfo implements Payload {
- private final String id;
- private final String direction;
- private final long amount;
- private final long minAmount;
- private final long price;
- private final String makerPaymentAccountId;
- private final String paymentMethodId;
- private final String paymentMethodShortName;
- private final String baseCurrencyCode;
- private final String counterCurrencyCode;
- private final long date;
- private final String ownerNodeAddress;
- private final String pubKeyRing; // TODO ?
- private final String versionNumber;
- private final int protocolVersion;
-
- public BsqSwapOfferInfo(BsqSwapOfferInfoBuilder builder) {
- this.id = builder.id;
- this.direction = builder.direction;
- this.amount = builder.amount;
- this.minAmount = builder.minAmount;
- this.price = builder.price;
- this.makerPaymentAccountId = builder.makerPaymentAccountId;
- this.paymentMethodId = builder.paymentMethodId;
- this.paymentMethodShortName = builder.paymentMethodShortName;
- this.baseCurrencyCode = builder.baseCurrencyCode;
- this.counterCurrencyCode = builder.counterCurrencyCode;
- this.date = builder.date;
- this.ownerNodeAddress = builder.ownerNodeAddress;
- this.pubKeyRing = builder.pubKeyRing;
- this.versionNumber = builder.versionNumber;
- this.protocolVersion = builder.protocolVersion;
- }
-
- public static BsqSwapOfferInfo toBsqSwapOfferInfo(Offer offer) {
- // TODO support triggerPrice
- return getAtomicOfferInfoBuilder(offer).build();
- }
-
- private static BsqSwapOfferInfoBuilder getAtomicOfferInfoBuilder(Offer offer) {
- return new BsqSwapOfferInfoBuilder()
- .withId(offer.getId())
- .withDirection(offer.getDirection().name())
- .withAmount(offer.getAmount().value)
- .withMinAmount(offer.getMinAmount().value)
- .withPrice(Objects.requireNonNull(offer.getPrice()).getValue())
- //.withMakerPaymentAccountId(offer.getOfferPayloadI().getMakerPaymentAccountId())
- //.withPaymentMethodId(offer.getOfferPayloadI().getPaymentMethodId())
- //.withPaymentMethodShortName(getPaymentMethodById(offer.getOfferPayloadI().getPaymentMethodId()).getShortName())
- .withBaseCurrencyCode(offer.getOfferPayloadBase().getBaseCurrencyCode())
- .withCounterCurrencyCode(offer.getOfferPayloadBase().getCounterCurrencyCode())
- .withDate(offer.getDate().getTime())
- .withOwnerNodeAddress(offer.getOfferPayloadBase().getOwnerNodeAddress().getFullAddress())
- .withPubKeyRing(offer.getOfferPayloadBase().getPubKeyRing().toString())
- .withVersionNumber(offer.getOfferPayloadBase().getVersionNr())
- .withProtocolVersion(offer.getOfferPayloadBase().getProtocolVersion());
- }
-
- ///////////////////////////////////////////////////////////////////////////////////////////
- // PROTO BUFFER
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- @Override
- public bisq.proto.grpc.BsqSwapOfferInfo toProtoMessage() {
- return bisq.proto.grpc.BsqSwapOfferInfo.newBuilder()
- .setId(id)
- .setDirection(direction)
- .setAmount(amount)
- .setMinAmount(minAmount)
- .setPrice(price)
- .setBaseCurrencyCode(baseCurrencyCode)
- .setCounterCurrencyCode(counterCurrencyCode)
- .setDate(date)
- .setOwnerNodeAddress(ownerNodeAddress)
- .setPubKeyRing(pubKeyRing)
- .setVersionNr(versionNumber)
- .setProtocolVersion(protocolVersion)
- .build();
- }
-
- public static BsqSwapOfferInfo fromProto(bisq.proto.grpc.BsqSwapOfferInfo proto) {
- return new BsqSwapOfferInfoBuilder()
- .withId(proto.getId())
- .withDirection(proto.getDirection())
- .withAmount(proto.getAmount())
- .withMinAmount(proto.getMinAmount())
- .withPrice(proto.getPrice())
- .withBaseCurrencyCode(proto.getBaseCurrencyCode())
- .withCounterCurrencyCode(proto.getCounterCurrencyCode())
- .withDate(proto.getDate())
- .withOwnerNodeAddress(proto.getOwnerNodeAddress())
- .withPubKeyRing(proto.getPubKeyRing())
- .withVersionNumber(proto.getVersionNr())
- .withProtocolVersion(proto.getProtocolVersion())
- .build();
- }
-
- public static class BsqSwapOfferInfoBuilder {
- private String id;
- private String direction;
- private long amount;
- private long minAmount;
- private long price;
- private String makerPaymentAccountId;
- private String paymentMethodId;
- private String paymentMethodShortName;
- private String baseCurrencyCode;
- private String counterCurrencyCode;
- private long date;
- private String ownerNodeAddress;
- private String pubKeyRing;
- private String versionNumber;
- private int protocolVersion;
-
- public BsqSwapOfferInfoBuilder withId(String id) {
- this.id = id;
- return this;
- }
-
- public BsqSwapOfferInfoBuilder withDirection(String direction) {
- this.direction = direction;
- return this;
- }
-
- public BsqSwapOfferInfoBuilder withAmount(long amount) {
- this.amount = amount;
- return this;
- }
-
- public BsqSwapOfferInfoBuilder withMinAmount(long minAmount) {
- this.minAmount = minAmount;
- return this;
- }
-
- public BsqSwapOfferInfoBuilder withPrice(long price) {
- this.price = price;
- return this;
- }
-
- public BsqSwapOfferInfoBuilder withMakerPaymentAccountId(String makerPaymentAccountId) {
- this.makerPaymentAccountId = makerPaymentAccountId;
- return this;
- }
-
- public BsqSwapOfferInfoBuilder withPaymentMethodId(String paymentMethodId) {
- this.paymentMethodId = paymentMethodId;
- return this;
- }
-
- public BsqSwapOfferInfoBuilder withPaymentMethodShortName(String paymentMethodShortName) {
- this.paymentMethodShortName = paymentMethodShortName;
- return this;
- }
-
- public BsqSwapOfferInfoBuilder withBaseCurrencyCode(String baseCurrencyCode) {
- this.baseCurrencyCode = baseCurrencyCode;
- return this;
- }
-
- public BsqSwapOfferInfoBuilder withCounterCurrencyCode(String counterCurrencyCode) {
- this.counterCurrencyCode = counterCurrencyCode;
- return this;
- }
-
- public BsqSwapOfferInfoBuilder withDate(long date) {
- this.date = date;
- return this;
- }
-
- public BsqSwapOfferInfoBuilder withOwnerNodeAddress(String ownerNodeAddress) {
- this.ownerNodeAddress = ownerNodeAddress;
- return this;
- }
-
- public BsqSwapOfferInfoBuilder withPubKeyRing(String pubKeyRing) {
- this.pubKeyRing = pubKeyRing;
- return this;
- }
-
- public BsqSwapOfferInfoBuilder withVersionNumber(String versionNumber) {
- this.versionNumber = versionNumber;
- return this;
- }
-
- public BsqSwapOfferInfoBuilder withProtocolVersion(int protocolVersion) {
- this.protocolVersion = protocolVersion;
- return this;
- }
-
- public BsqSwapOfferInfo build() {
- return new BsqSwapOfferInfo(this);
- }
- }
-}
diff --git a/core/src/main/java/bisq/core/api/model/BsqSwapTradeInfo.java b/core/src/main/java/bisq/core/api/model/BsqSwapTradeInfo.java
index c24dcca0163..d46cf877a02 100644
--- a/core/src/main/java/bisq/core/api/model/BsqSwapTradeInfo.java
+++ b/core/src/main/java/bisq/core/api/model/BsqSwapTradeInfo.java
@@ -17,100 +17,67 @@
package bisq.core.api.model;
+import bisq.core.api.model.builder.BsqSwapTradeInfoBuilder;
import bisq.core.trade.model.bsq_swap.BsqSwapTrade;
import bisq.common.Payload;
import lombok.EqualsAndHashCode;
import lombok.Getter;
-import lombok.ToString;
-
-import static bisq.core.api.model.BsqSwapOfferInfo.toBsqSwapOfferInfo;
@EqualsAndHashCode
-@ToString
@Getter
public class BsqSwapTradeInfo implements Payload {
- private final BsqSwapOfferInfo bsqSwapOffer;
- private final String tradeId;
- private final String tempTradingPeerNodeAddress;
- private final String peerNodeAddress;
private final String txId;
private final long bsqTradeAmount;
- private final long bsqMaxTradeAmount;
- private final long bsqMinTradeAmount;
private final long btcTradeAmount;
- private final long btcMaxTradeAmount;
- private final long btcMinTradeAmount;
- private final long tradePrice;
private final long bsqMakerTradeFee;
private final long bsqTakerTradeFee;
private final long txFeePerVbyte;
- private final long txFee;
private final String makerBsqAddress;
private final String makerBtcAddress;
private final String takerBsqAddress;
private final String takerBtcAddress;
- private final long takeOfferDate;
- private final String state;
+ private final long numConfirmations;
private final String errorMessage;
public BsqSwapTradeInfo(BsqSwapTradeInfoBuilder builder) {
- this.bsqSwapOffer = builder.bsqSwapOfferInfo;
- this.tradeId = builder.tradeId;
- this.tempTradingPeerNodeAddress = builder.tempTradingPeerNodeAddress;
- this.peerNodeAddress = builder.peerNodeAddress;
- this.txId = builder.txId;
- this.bsqTradeAmount = builder.bsqTradeAmount;
- this.bsqMaxTradeAmount = builder.bsqMaxTradeAmount;
- this.bsqMinTradeAmount = builder.bsqMinTradeAmount;
- this.btcTradeAmount = builder.btcTradeAmount;
- this.btcMaxTradeAmount = builder.btcMaxTradeAmount;
- this.btcMinTradeAmount = builder.btcMinTradeAmount;
- this.tradePrice = builder.tradePrice;
- this.bsqMakerTradeFee = builder.bsqMakerTradeFee;
- this.bsqTakerTradeFee = builder.bsqTakerTradeFee;
- this.txFeePerVbyte = builder.txFeePerVbyte;
- this.txFee = builder.txFee;
- this.makerBsqAddress = builder.makerBsqAddress;
- this.makerBtcAddress = builder.makerBtcAddress;
- this.takerBsqAddress = builder.takerBsqAddress;
- this.takerBtcAddress = builder.takerBtcAddress;
- this.takeOfferDate = builder.takeOfferDate;
- this.state = builder.state;
- this.errorMessage = builder.errorMessage;
- }
-
- public static BsqSwapTradeInfo toBsqSwapTradeInfo(BsqSwapTrade trade) {
- return toBsqSwapTradeInfo(trade, null);
+ this.txId = builder.getTxId();
+ this.bsqTradeAmount = builder.getBsqTradeAmount();
+ this.btcTradeAmount = builder.getBtcTradeAmount();
+ this.bsqMakerTradeFee = builder.getBsqMakerTradeFee();
+ this.bsqTakerTradeFee = builder.getBsqTakerTradeFee();
+ this.txFeePerVbyte = builder.getTxFeePerVbyte();
+ this.makerBsqAddress = builder.getMakerBsqAddress();
+ this.makerBtcAddress = builder.getMakerBtcAddress();
+ this.takerBsqAddress = builder.getTakerBsqAddress();
+ this.takerBtcAddress = builder.getTakerBtcAddress();
+ this.numConfirmations = builder.getNumConfirmations();
+ this.errorMessage = builder.getErrorMessage();
}
- //TODO
- public static BsqSwapTradeInfo toBsqSwapTradeInfo(BsqSwapTrade trade, String role) {
+ public static BsqSwapTradeInfo toBsqSwapTradeInfo(BsqSwapTrade trade,
+ boolean wasMyOffer,
+ int numConfirmations) {
+ var protocolModel = trade.getBsqSwapProtocolModel();
+ var swapPeer = protocolModel.getTradePeer();
+ var makerBsqAddress = wasMyOffer ? protocolModel.getBsqAddress() : swapPeer.getBsqAddress();
+ var makerBtcAddress = wasMyOffer ? protocolModel.getBtcAddress() : swapPeer.getBtcAddress();
+ var takerBsqAddress = wasMyOffer ? swapPeer.getBsqAddress() : protocolModel.getBsqAddress();
+ var takerBtcAddress = wasMyOffer ? swapPeer.getBtcAddress() : protocolModel.getBtcAddress();
return new BsqSwapTradeInfoBuilder()
- .withBsqSwapOffer(toBsqSwapOfferInfo(trade.getOffer()))
- .withTradeId(trade.getId())
- .withTempTradingPeerNodeAddress(trade.getBsqSwapProtocolModel().getTempTradingPeerNodeAddress().getFullAddress())
- .withPeerNodeAddress(trade.getTradingPeerNodeAddress().getFullAddress())
.withTxId(trade.getTxId())
- /* .withBsqTradeAmount(trade.getBsqSwapProtocolModel().getBsqTradeAmount())
- .withBsqMaxTradeAmount(trade.getBsqSwapProtocolModel().getBsqMaxTradeAmount())
- .withBsqMinTradeAmount(trade.getBsqSwapProtocolModel().getBsqMinTradeAmount())
- .withBtcTradeAmount(trade.getBsqSwapProtocolModel().getBtcTradeAmount())
- .withBtcMaxTradeAmount(trade.getBsqSwapProtocolModel().getBtcMaxTradeAmount())
- .withBtcMinTradeAmount(trade.getBsqSwapProtocolModel().getBtcMinTradeAmount())
- .withTradePrice(trade.getBsqSwapProtocolModel().getTradePrice())
- .withBsqMakerTradeFee(trade.getBsqSwapProtocolModel().getBsqMakerTradeFee())
- .withBsqTakerTradeFee(trade.getBsqSwapProtocolModel().getBsqTakerTradeFee())
- .withTxFeePerVbyte(trade.getBsqSwapProtocolModel().getTxFeePerVbyte())
- .withTxFee(trade.getBsqSwapProtocolModel().getTxFee())
- .withMakerBsqAddress(trade.getBsqSwapProtocolModel().getMakerBsqAddress())
- .withMakerBtcAddress(trade.getBsqSwapProtocolModel().getMakerBtcAddress())
- .withTakerBsqAddress(trade.getBsqSwapProtocolModel().getTakerBsqAddress())
- .withTakerBtcAddress(trade.getBsqSwapProtocolModel().getTakerBtcAddress())*/
- .withTakeOfferDate(trade.getTakeOfferDate())
- .withState(trade.getTradeState().name())
+ .withBsqTradeAmount(trade.getBsqTradeAmount())
+ .withBtcTradeAmount(trade.getAmountAsLong())
+ .withBsqMakerTradeFee(trade.getMakerFeeAsLong())
+ .withBsqTakerTradeFee(trade.getTakerFeeAsLong())
+ .withTxFeePerVbyte(trade.getTxFeePerVbyte())
+ .withMakerBsqAddress(makerBsqAddress)
+ .withMakerBtcAddress(makerBtcAddress)
+ .withTakerBsqAddress(takerBsqAddress)
+ .withTakerBtcAddress(takerBtcAddress)
+ .withNumConfirmations(numConfirmations)
.withErrorMessage(trade.getErrorMessage())
.build();
}
@@ -122,202 +89,53 @@ public static BsqSwapTradeInfo toBsqSwapTradeInfo(BsqSwapTrade trade, String rol
@Override
public bisq.proto.grpc.BsqSwapTradeInfo toProtoMessage() {
return bisq.proto.grpc.BsqSwapTradeInfo.newBuilder()
- .setBsqSwapOfferInfo(bsqSwapOffer.toProtoMessage())
- .setTradeId(tradeId)
- .setTempTradingPeerNodeAddress(tempTradingPeerNodeAddress != null ? tempTradingPeerNodeAddress : "")
- .setPeerNodeAddress(peerNodeAddress != null ? peerNodeAddress : "")
.setTxId(txId != null ? txId : "")
.setBsqTradeAmount(bsqTradeAmount)
- .setBsqMaxTradeAmount(bsqMaxTradeAmount)
- .setBsqMinTradeAmount(bsqMinTradeAmount)
.setBtcTradeAmount(btcTradeAmount)
- .setBtcMaxTradeAmount(btcMaxTradeAmount)
- .setBtcMinTradeAmount(btcMinTradeAmount)
- .setTradePrice(tradePrice)
.setBsqMakerTradeFee(bsqMakerTradeFee)
.setBsqTakerTradeFee(bsqTakerTradeFee)
.setTxFeePerVbyte(txFeePerVbyte)
- .setTxFee(txFee)
.setMakerBsqAddress(makerBsqAddress != null ? makerBsqAddress : "")
.setTakerBsqAddress(takerBsqAddress != null ? takerBsqAddress : "")
.setMakerBtcAddress(makerBtcAddress != null ? makerBtcAddress : "")
.setTakerBtcAddress(takerBtcAddress != null ? takerBtcAddress : "")
- .setTakeOfferDate(takeOfferDate)
- .setState(state)
- .setErrorMessage(errorMessage != null ? errorMessage : "")
+ .setTakerBtcAddress(takerBtcAddress != null ? takerBtcAddress : "")
+ .setNumConfirmations(numConfirmations)
.build();
}
public static BsqSwapTradeInfo fromProto(bisq.proto.grpc.BsqSwapTradeInfo proto) {
return new BsqSwapTradeInfoBuilder()
- .withBsqSwapOffer(BsqSwapOfferInfo.fromProto(proto.getBsqSwapOfferInfo()))
- .withTradeId(proto.getTradeId())
- .withTempTradingPeerNodeAddress(proto.getTempTradingPeerNodeAddress())
- .withPeerNodeAddress(proto.getPeerNodeAddress())
.withTxId(proto.getTxId())
.withBsqTradeAmount(proto.getBsqTradeAmount())
- .withBsqMaxTradeAmount(proto.getBsqMaxTradeAmount())
- .withBsqMinTradeAmount(proto.getBsqMinTradeAmount())
.withBtcTradeAmount(proto.getBtcTradeAmount())
- .withBtcMaxTradeAmount(proto.getBtcMaxTradeAmount())
- .withBtcMinTradeAmount(proto.getBtcMinTradeAmount())
- .withTradePrice(proto.getTradePrice())
.withBsqMakerTradeFee(proto.getBsqMakerTradeFee())
.withBsqTakerTradeFee(proto.getBsqTakerTradeFee())
.withTxFeePerVbyte(proto.getTxFeePerVbyte())
- .withTxFee(proto.getTxFee())
.withMakerBsqAddress(proto.getMakerBsqAddress())
.withMakerBtcAddress(proto.getMakerBtcAddress())
.withTakerBsqAddress(proto.getTakerBsqAddress())
.withTakerBtcAddress(proto.getTakerBtcAddress())
- .withTakeOfferDate(proto.getTakeOfferDate())
- .withState(proto.getState())
+ .withNumConfirmations(proto.getNumConfirmations())
.withErrorMessage(proto.getErrorMessage())
.build();
}
- public static class BsqSwapTradeInfoBuilder {
- private BsqSwapOfferInfo bsqSwapOfferInfo;
- private String tradeId;
- private String tempTradingPeerNodeAddress;
- private String peerNodeAddress;
- private String txId;
- private long bsqTradeAmount;
- private long bsqMaxTradeAmount;
- private long bsqMinTradeAmount;
- private long btcTradeAmount;
- private long btcMaxTradeAmount;
- private long btcMinTradeAmount;
- private long tradePrice;
- private long bsqMakerTradeFee;
- private long bsqTakerTradeFee;
- private long txFeePerVbyte;
- private long txFee;
- private String makerBsqAddress;
- private String makerBtcAddress;
- private String takerBsqAddress;
- private String takerBtcAddress;
- private long takeOfferDate;
- private String state;
- private String errorMessage;
-
- public BsqSwapTradeInfoBuilder withBsqSwapOffer(BsqSwapOfferInfo bsqSwapOfferInfo) {
- this.bsqSwapOfferInfo = bsqSwapOfferInfo;
- return this;
- }
-
- public BsqSwapTradeInfoBuilder withTradeId(String tradeId) {
- this.tradeId = tradeId;
- return this;
- }
-
- public BsqSwapTradeInfoBuilder withTempTradingPeerNodeAddress(String tempTradingPeerNodeAddress) {
- this.tempTradingPeerNodeAddress = tempTradingPeerNodeAddress;
- return this;
- }
-
- public BsqSwapTradeInfoBuilder withPeerNodeAddress(String peerNodeAddress) {
- this.peerNodeAddress = peerNodeAddress;
- return this;
- }
-
- public BsqSwapTradeInfoBuilder withTxId(String txId) {
- this.txId = txId;
- return this;
- }
-
- public BsqSwapTradeInfoBuilder withBsqTradeAmount(long bsqTradeAmount) {
- this.bsqTradeAmount = bsqTradeAmount;
- return this;
- }
-
- public BsqSwapTradeInfoBuilder withBsqMaxTradeAmount(long bsqMaxTradeAmount) {
- this.bsqMaxTradeAmount = bsqMaxTradeAmount;
- return this;
- }
-
- public BsqSwapTradeInfoBuilder withBsqMinTradeAmount(long bsqMinTradeAmount) {
- this.bsqMinTradeAmount = bsqMinTradeAmount;
- return this;
- }
-
- public BsqSwapTradeInfoBuilder withBtcTradeAmount(long btcTradeAmount) {
- this.btcTradeAmount = btcTradeAmount;
- return this;
- }
-
- public BsqSwapTradeInfoBuilder withBtcMaxTradeAmount(long btcMaxTradeAmount) {
- this.btcMaxTradeAmount = btcMaxTradeAmount;
- return this;
- }
-
- public BsqSwapTradeInfoBuilder withBtcMinTradeAmount(long btcMinTradeAmount) {
- this.btcMinTradeAmount = btcMinTradeAmount;
- return this;
- }
-
- public BsqSwapTradeInfoBuilder withTradePrice(long tradePrice) {
- this.tradePrice = tradePrice;
- return this;
- }
-
- public BsqSwapTradeInfoBuilder withBsqMakerTradeFee(long bsqMakerTradeFee) {
- this.bsqMakerTradeFee = bsqMakerTradeFee;
- return this;
- }
-
- public BsqSwapTradeInfoBuilder withBsqTakerTradeFee(long bsqTakerTradeFee) {
- this.bsqTakerTradeFee = bsqTakerTradeFee;
- return this;
- }
-
- public BsqSwapTradeInfoBuilder withTxFeePerVbyte(long txFeePerVbyte) {
- this.txFeePerVbyte = txFeePerVbyte;
- return this;
- }
-
- public BsqSwapTradeInfoBuilder withTxFee(long txFee) {
- this.txFee = txFee;
- return this;
- }
-
- public BsqSwapTradeInfoBuilder withMakerBsqAddress(String makerBsqAddress) {
- this.makerBsqAddress = makerBsqAddress;
- return this;
- }
-
- public BsqSwapTradeInfoBuilder withMakerBtcAddress(String makerBtcAddress) {
- this.makerBtcAddress = makerBtcAddress;
- return this;
- }
-
- public BsqSwapTradeInfoBuilder withTakerBsqAddress(String takerBsqAddress) {
- this.takerBsqAddress = takerBsqAddress;
- return this;
- }
-
- public BsqSwapTradeInfoBuilder withTakerBtcAddress(String takerBtcAddress) {
- this.takerBtcAddress = takerBtcAddress;
- return this;
- }
-
- public BsqSwapTradeInfoBuilder withTakeOfferDate(long takeOfferDate) {
- this.takeOfferDate = takeOfferDate;
- return this;
- }
-
- public BsqSwapTradeInfoBuilder withState(String state) {
- this.state = state;
- return this;
- }
-
- public BsqSwapTradeInfoBuilder withErrorMessage(String errorMessage) {
- this.errorMessage = errorMessage;
- return this;
- }
-
- public BsqSwapTradeInfo build() {
- return new BsqSwapTradeInfo(this);
- }
+ @Override
+ public String toString() {
+ return "BsqSwapTradeInfo{" +
+ ", txId='" + txId + '\'' +
+ ", bsqTradeAmount=" + bsqTradeAmount +
+ ", btcTradeAmount=" + btcTradeAmount +
+ ", bsqMakerTradeFee=" + bsqMakerTradeFee +
+ ", bsqTakerTradeFee=" + bsqTakerTradeFee +
+ ", txFeePerVbyte=" + txFeePerVbyte +
+ ", makerBsqAddress='" + makerBsqAddress + '\'' +
+ ", makerBtcAddress='" + makerBtcAddress + '\'' +
+ ", takerBsqAddress='" + takerBsqAddress + '\'' +
+ ", takerBtcAddress='" + takerBtcAddress + '\'' +
+ ", numConfirmations='" + numConfirmations + '\'' +
+ ", errorMessage='" + errorMessage + '\'' +
+ '}';
}
}
diff --git a/core/src/main/java/bisq/core/api/model/ContractInfo.java b/core/src/main/java/bisq/core/api/model/ContractInfo.java
index 404335c9c7f..d4ce1e8ccb4 100644
--- a/core/src/main/java/bisq/core/api/model/ContractInfo.java
+++ b/core/src/main/java/bisq/core/api/model/ContractInfo.java
@@ -73,6 +73,7 @@ public ContractInfo(String buyerNodeAddress,
// For transmitting TradeInfo messages when no contract is available.
+ // TODO Is this necessary as protobuf will send a DEFAULT_INSTANCE.
public static Supplier emptyContract = () ->
new ContractInfo("",
"",
diff --git a/core/src/main/java/bisq/core/api/model/OfferInfo.java b/core/src/main/java/bisq/core/api/model/OfferInfo.java
index 67cee988a3b..6cf635cb3b2 100644
--- a/core/src/main/java/bisq/core/api/model/OfferInfo.java
+++ b/core/src/main/java/bisq/core/api/model/OfferInfo.java
@@ -17,17 +17,19 @@
package bisq.core.api.model;
+import bisq.core.api.model.builder.OfferInfoBuilder;
import bisq.core.offer.Offer;
import bisq.core.offer.OpenOffer;
+import bisq.core.util.coin.CoinUtil;
import bisq.common.Payload;
-import java.util.Objects;
-
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
+import static java.util.Objects.requireNonNull;
+
@EqualsAndHashCode
@ToString
@Getter
@@ -56,86 +58,95 @@ public class OfferInfo implements Payload {
private final String paymentAccountId;
private final String paymentMethodId;
private final String paymentMethodShortName;
- // For fiat offer the baseCurrencyCode is BTC and the counterCurrencyCode is the fiat currency
- // For altcoin offers it is the opposite. baseCurrencyCode is the altcoin and the counterCurrencyCode is BTC.
+ // Fiat offer: baseCurrencyCode = BTC, counterCurrencyCode = fiat ccy code.
+ // Altcoin offer: baseCurrencyCode = altcoin ccy code, counterCurrencyCode = BTC.
private final String baseCurrencyCode;
private final String counterCurrencyCode;
private final long date;
private final String state;
private final boolean isActivated;
- private boolean isMyOffer; // Not final -- may be re-set after instantiation.
+ private final boolean isMyOffer;
private final boolean isMyPendingOffer;
+ private final boolean isBsqSwapOffer;
+ private final String ownerNodeAddress;
+ private final String pubKeyRing;
+ private final String versionNumber;
+ private final int protocolVersion;
public OfferInfo(OfferInfoBuilder builder) {
- this.id = builder.id;
- this.direction = builder.direction;
- this.price = builder.price;
- this.useMarketBasedPrice = builder.useMarketBasedPrice;
- this.marketPriceMargin = builder.marketPriceMargin;
- this.amount = builder.amount;
- this.minAmount = builder.minAmount;
- this.volume = builder.volume;
- this.minVolume = builder.minVolume;
- this.txFee = builder.txFee;
- this.makerFee = builder.makerFee;
- this.offerFeePaymentTxId = builder.offerFeePaymentTxId;
- this.buyerSecurityDeposit = builder.buyerSecurityDeposit;
- this.sellerSecurityDeposit = builder.sellerSecurityDeposit;
- this.triggerPrice = builder.triggerPrice;
- this.isCurrencyForMakerFeeBtc = builder.isCurrencyForMakerFeeBtc;
- this.paymentAccountId = builder.paymentAccountId;
- this.paymentMethodId = builder.paymentMethodId;
- this.paymentMethodShortName = builder.paymentMethodShortName;
- this.baseCurrencyCode = builder.baseCurrencyCode;
- this.counterCurrencyCode = builder.counterCurrencyCode;
- this.date = builder.date;
- this.state = builder.state;
- this.isActivated = builder.isActivated;
- this.isMyOffer = builder.isMyOffer;
- this.isMyPendingOffer = builder.isMyPendingOffer;
+ this.id = builder.getId();
+ this.direction = builder.getDirection();
+ this.price = builder.getPrice();
+ this.useMarketBasedPrice = builder.isUseMarketBasedPrice();
+ this.marketPriceMargin = builder.getMarketPriceMargin();
+ this.amount = builder.getAmount();
+ this.minAmount = builder.getMinAmount();
+ this.volume = builder.getVolume();
+ this.minVolume = builder.getMinVolume();
+ this.txFee = builder.getTxFee();
+ this.makerFee = builder.getMakerFee();
+ this.offerFeePaymentTxId = builder.getOfferFeePaymentTxId();
+ this.buyerSecurityDeposit = builder.getBuyerSecurityDeposit();
+ this.sellerSecurityDeposit = builder.getSellerSecurityDeposit();
+ this.triggerPrice = builder.getTriggerPrice();
+ this.isCurrencyForMakerFeeBtc = builder.isCurrencyForMakerFeeBtc();
+ this.paymentAccountId = builder.getPaymentAccountId();
+ this.paymentMethodId = builder.getPaymentMethodId();
+ this.paymentMethodShortName = builder.getPaymentMethodShortName();
+ this.baseCurrencyCode = builder.getBaseCurrencyCode();
+ this.counterCurrencyCode = builder.getCounterCurrencyCode();
+ this.date = builder.getDate();
+ this.state = builder.getState();
+ this.isActivated = builder.isActivated();
+ this.isMyOffer = builder.isMyOffer();
+ this.isMyPendingOffer = builder.isMyPendingOffer();
+ this.isBsqSwapOffer = builder.isBsqSwapOffer();
+ this.ownerNodeAddress = builder.getOwnerNodeAddress();
+ this.pubKeyRing = builder.getPubKeyRing();
+ this.versionNumber = builder.getVersionNumber();
+ this.protocolVersion = builder.getProtocolVersion();
}
- // Allow isMyOffer to be set on a new offer's OfferInfo instance.
- public void setIsMyOffer(boolean isMyOffer) {
- this.isMyOffer = isMyOffer;
+ public static OfferInfo toMyOfferInfo(Offer offer) {
+ return getBuilder(offer, true).build();
}
public static OfferInfo toOfferInfo(Offer offer) {
// Assume the offer is not mine, but isMyOffer can be reset to true, i.e., when
// calling TradeInfo toTradeInfo(Trade trade, String role, boolean isMyOffer);
- return getOfferInfoBuilder(offer, false).build();
+ return getBuilder(offer, false).build();
}
- public static OfferInfo toPendingOfferInfo(Offer myNewOffer) {
+ public static OfferInfo toMyPendingOfferInfo(Offer myNewOffer) {
// Use this to build an OfferInfo instance when a new OpenOffer is being
// prepared, and no valid OpenOffer state (AVAILABLE, DEACTIVATED) exists.
// It is needed for the CLI's 'createoffer' output, which has a boolean 'ENABLED'
// column that will show a PENDING value when this.isMyPendingOffer = true.
- return getOfferInfoBuilder(myNewOffer, true)
+ return getBuilder(myNewOffer, true)
.withIsMyPendingOffer(true)
.build();
}
- public static OfferInfo toOfferInfo(OpenOffer openOffer) {
+ public static OfferInfo toMyOfferInfo(OpenOffer openOffer) {
// An OpenOffer is always my offer.
- return getOfferInfoBuilder(openOffer.getOffer(), true)
+ return getBuilder(openOffer.getOffer(), true)
.withTriggerPrice(openOffer.getTriggerPrice())
.withIsActivated(!openOffer.isDeactivated())
.build();
}
- private static OfferInfoBuilder getOfferInfoBuilder(Offer offer, boolean isMyOffer) {
+ private static OfferInfoBuilder getBuilder(Offer offer, boolean isMyOffer) {
return new OfferInfoBuilder()
.withId(offer.getId())
.withDirection(offer.getDirection().name())
- .withPrice(Objects.requireNonNull(offer.getPrice()).getValue())
+ .withPrice(requireNonNull(offer.getPrice()).getValue())
.withUseMarketBasedPrice(offer.isUseMarketBasedPrice())
.withMarketPriceMargin(offer.getMarketPriceMargin())
.withAmount(offer.getAmount().value)
.withMinAmount(offer.getMinAmount().value)
- .withVolume(Objects.requireNonNull(offer.getVolume()).getValue())
- .withMinVolume(Objects.requireNonNull(offer.getMinVolume()).getValue())
- .withMakerFee(offer.getMakerFee().value)
+ .withVolume(requireNonNull(offer.getVolume()).getValue())
+ .withMinVolume(requireNonNull(offer.getMinVolume()).getValue())
+ .withMakerFee(getMakerFee(offer, isMyOffer))
.withTxFee(offer.getTxFee().value)
.withOfferFeePaymentTxId(offer.getOfferFeePaymentTxId())
.withBuyerSecurityDeposit(offer.getBuyerSecurityDeposit().value)
@@ -148,7 +159,18 @@ private static OfferInfoBuilder getOfferInfoBuilder(Offer offer, boolean isMyOff
.withCounterCurrencyCode(offer.getCounterCurrencyCode())
.withDate(offer.getDate().getTime())
.withState(offer.getState().name())
- .withIsMyOffer(isMyOffer);
+ .withIsMyOffer(isMyOffer)
+ .withIsBsqSwapOffer(offer.isBsqSwapOffer())
+ .withOwnerNodeAddress(offer.getOfferPayloadBase().getOwnerNodeAddress().getFullAddress())
+ .withPubKeyRing(offer.getOfferPayloadBase().getPubKeyRing().toString())
+ .withVersionNumber(offer.getOfferPayloadBase().getVersionNr())
+ .withProtocolVersion(offer.getOfferPayloadBase().getProtocolVersion());
+ }
+
+ private static long getMakerFee(Offer offer, boolean isMyOffer) {
+ return isMyOffer
+ ? requireNonNull(CoinUtil.getMakerFee(false, offer.getAmount())).value
+ : 0;
}
///////////////////////////////////////////////////////////////////////////////////////////
@@ -169,7 +191,7 @@ public bisq.proto.grpc.OfferInfo toProtoMessage() {
.setMinVolume(minVolume)
.setMakerFee(makerFee)
.setTxFee(txFee)
- .setOfferFeePaymentTxId(offerFeePaymentTxId)
+ .setOfferFeePaymentTxId(isBsqSwapOffer ? "" : offerFeePaymentTxId)
.setBuyerSecurityDeposit(buyerSecurityDeposit)
.setSellerSecurityDeposit(sellerSecurityDeposit)
.setTriggerPrice(triggerPrice)
@@ -184,6 +206,11 @@ public bisq.proto.grpc.OfferInfo toProtoMessage() {
.setIsActivated(isActivated)
.setIsMyOffer(isMyOffer)
.setIsMyPendingOffer(isMyPendingOffer)
+ .setIsBsqSwapOffer(isBsqSwapOffer)
+ .setOwnerNodeAddress(ownerNodeAddress)
+ .setPubKeyRing(pubKeyRing)
+ .setVersionNr(versionNumber)
+ .setProtocolVersion(protocolVersion)
.build();
}
@@ -216,175 +243,11 @@ public static OfferInfo fromProto(bisq.proto.grpc.OfferInfo proto) {
.withIsActivated(proto.getIsActivated())
.withIsMyOffer(proto.getIsMyOffer())
.withIsMyPendingOffer(proto.getIsMyPendingOffer())
+ .withIsBsqSwapOffer(proto.getIsBsqSwapOffer())
+ .withOwnerNodeAddress(proto.getOwnerNodeAddress())
+ .withPubKeyRing(proto.getPubKeyRing())
+ .withVersionNumber(proto.getVersionNr())
+ .withProtocolVersion(proto.getProtocolVersion())
.build();
}
-
- /*
- * OfferInfoBuilder helps avoid bungling use of a large OfferInfo constructor
- * argument list. If consecutive argument values of the same type are not
- * ordered correctly, the compiler won't complain but the resulting bugs could
- * be hard to find and fix.
- */
- public static class OfferInfoBuilder {
- private String id;
- private String direction;
- private long price;
- private boolean useMarketBasedPrice;
- private double marketPriceMargin;
- private long amount;
- private long minAmount;
- private long volume;
- private long minVolume;
- private long txFee;
- private long makerFee;
- private String offerFeePaymentTxId;
- private long buyerSecurityDeposit;
- private long sellerSecurityDeposit;
- private long triggerPrice;
- private boolean isCurrencyForMakerFeeBtc;
- private String paymentAccountId;
- private String paymentMethodId;
- private String paymentMethodShortName;
- private String baseCurrencyCode;
- private String counterCurrencyCode;
- private long date;
- private String state;
- private boolean isActivated;
- private boolean isMyOffer;
- private boolean isMyPendingOffer;
-
- public OfferInfoBuilder withId(String id) {
- this.id = id;
- return this;
- }
-
- public OfferInfoBuilder withDirection(String direction) {
- this.direction = direction;
- return this;
- }
-
- public OfferInfoBuilder withPrice(long price) {
- this.price = price;
- return this;
- }
-
- public OfferInfoBuilder withUseMarketBasedPrice(boolean useMarketBasedPrice) {
- this.useMarketBasedPrice = useMarketBasedPrice;
- return this;
- }
-
- public OfferInfoBuilder withMarketPriceMargin(double useMarketBasedPrice) {
- this.marketPriceMargin = useMarketBasedPrice;
- return this;
- }
-
- public OfferInfoBuilder withAmount(long amount) {
- this.amount = amount;
- return this;
- }
-
- public OfferInfoBuilder withMinAmount(long minAmount) {
- this.minAmount = minAmount;
- return this;
- }
-
- public OfferInfoBuilder withVolume(long volume) {
- this.volume = volume;
- return this;
- }
-
- public OfferInfoBuilder withMinVolume(long minVolume) {
- this.minVolume = minVolume;
- return this;
- }
-
- public OfferInfoBuilder withTxFee(long txFee) {
- this.txFee = txFee;
- return this;
- }
-
- public OfferInfoBuilder withMakerFee(long makerFee) {
- this.makerFee = makerFee;
- return this;
- }
-
- public OfferInfoBuilder withOfferFeePaymentTxId(String offerFeePaymentTxId) {
- this.offerFeePaymentTxId = offerFeePaymentTxId;
- return this;
- }
-
- public OfferInfoBuilder withBuyerSecurityDeposit(long buyerSecurityDeposit) {
- this.buyerSecurityDeposit = buyerSecurityDeposit;
- return this;
- }
-
- public OfferInfoBuilder withSellerSecurityDeposit(long sellerSecurityDeposit) {
- this.sellerSecurityDeposit = sellerSecurityDeposit;
- return this;
- }
-
- public OfferInfoBuilder withTriggerPrice(long triggerPrice) {
- this.triggerPrice = triggerPrice;
- return this;
- }
-
- public OfferInfoBuilder withIsCurrencyForMakerFeeBtc(boolean isCurrencyForMakerFeeBtc) {
- this.isCurrencyForMakerFeeBtc = isCurrencyForMakerFeeBtc;
- return this;
- }
-
- public OfferInfoBuilder withPaymentAccountId(String paymentAccountId) {
- this.paymentAccountId = paymentAccountId;
- return this;
- }
-
- public OfferInfoBuilder withPaymentMethodId(String paymentMethodId) {
- this.paymentMethodId = paymentMethodId;
- return this;
- }
-
- public OfferInfoBuilder withPaymentMethodShortName(String paymentMethodShortName) {
- this.paymentMethodShortName = paymentMethodShortName;
- return this;
- }
-
- public OfferInfoBuilder withBaseCurrencyCode(String baseCurrencyCode) {
- this.baseCurrencyCode = baseCurrencyCode;
- return this;
- }
-
- public OfferInfoBuilder withCounterCurrencyCode(String counterCurrencyCode) {
- this.counterCurrencyCode = counterCurrencyCode;
- return this;
- }
-
- public OfferInfoBuilder withDate(long date) {
- this.date = date;
- return this;
- }
-
- public OfferInfoBuilder withState(String state) {
- this.state = state;
- return this;
- }
-
- public OfferInfoBuilder withIsActivated(boolean isActivated) {
- this.isActivated = isActivated;
- return this;
- }
-
- public OfferInfoBuilder withIsMyOffer(boolean isMyOffer) {
- this.isMyOffer = isMyOffer;
- return this;
- }
-
- public OfferInfoBuilder withIsMyPendingOffer(boolean isMyPendingOffer) {
- this.isMyPendingOffer = isMyPendingOffer;
- return this;
- }
-
- public OfferInfo build() {
- return new OfferInfo(this);
- }
- }
}
diff --git a/core/src/main/java/bisq/core/api/model/TradeInfo.java b/core/src/main/java/bisq/core/api/model/TradeInfo.java
index 024eb69fa2f..b8eb474e6ed 100644
--- a/core/src/main/java/bisq/core/api/model/TradeInfo.java
+++ b/core/src/main/java/bisq/core/api/model/TradeInfo.java
@@ -17,18 +17,22 @@
package bisq.core.api.model;
+import bisq.core.api.model.builder.TradeInfoV1Builder;
+import bisq.core.trade.model.TradeModel;
import bisq.core.trade.model.bisq_v1.Contract;
import bisq.core.trade.model.bisq_v1.Trade;
+import bisq.core.trade.model.bsq_swap.BsqSwapTrade;
import bisq.common.Payload;
-import java.util.Objects;
-
import lombok.EqualsAndHashCode;
import lombok.Getter;
+import static bisq.core.api.model.BsqSwapTradeInfo.toBsqSwapTradeInfo;
+import static bisq.core.api.model.OfferInfo.toMyOfferInfo;
import static bisq.core.api.model.OfferInfo.toOfferInfo;
import static bisq.core.api.model.PaymentAccountPayloadInfo.toPaymentAccountPayloadInfo;
+import static java.util.Objects.requireNonNull;
@EqualsAndHashCode
@Getter
@@ -38,6 +42,7 @@ public class TradeInfo implements Payload {
// lighter weight TradeInfo proto wrapper instead, containing just enough fields to
// view and interact with trades.
+ // Bisq v1 trade protocol fields (some are in common with the BSQ Swap protocol).
private final OfferInfo offer;
private final String tradeId;
private final String shortId;
@@ -64,41 +69,88 @@ public class TradeInfo implements Payload {
private final boolean isWithdrawn;
private final String contractAsJson;
private final ContractInfo contract;
+ // Optional BSQ swap trade protocol details (post v1).
+ private BsqSwapTradeInfo bsqSwapTradeInfo;
+
+ public TradeInfo(TradeInfoV1Builder builder) {
+ this.offer = builder.getOffer();
+ this.tradeId = builder.getTradeId();
+ this.shortId = builder.getShortId();
+ this.date = builder.getDate();
+ this.role = builder.getRole();
+ this.isCurrencyForTakerFeeBtc = builder.isCurrencyForTakerFeeBtc();
+ this.txFeeAsLong = builder.getTxFeeAsLong();
+ this.takerFeeAsLong = builder.getTakerFeeAsLong();
+ this.takerFeeTxId = builder.getTakerFeeTxId();
+ this.depositTxId = builder.getDepositTxId();
+ this.payoutTxId = builder.getPayoutTxId();
+ this.tradeAmountAsLong = builder.getTradeAmountAsLong();
+ this.tradePrice = builder.getTradePrice();
+ this.tradeVolume = builder.getTradeVolume();
+ this.tradingPeerNodeAddress = builder.getTradingPeerNodeAddress();
+ this.state = builder.getState();
+ this.phase = builder.getPhase();
+ this.tradePeriodState = builder.getTradePeriodState();
+ this.isDepositPublished = builder.isDepositPublished();
+ this.isDepositConfirmed = builder.isDepositConfirmed();
+ this.isFiatSent = builder.isFiatSent();
+ this.isFiatReceived = builder.isFiatReceived();
+ this.isPayoutPublished = builder.isPayoutPublished();
+ this.isWithdrawn = builder.isWithdrawn();
+ this.contractAsJson = builder.getContractAsJson();
+ this.contract = builder.getContract();
+ this.bsqSwapTradeInfo = null;
+ }
- public TradeInfo(TradeInfoBuilder builder) {
- this.offer = builder.offer;
- this.tradeId = builder.tradeId;
- this.shortId = builder.shortId;
- this.date = builder.date;
- this.role = builder.role;
- this.isCurrencyForTakerFeeBtc = builder.isCurrencyForTakerFeeBtc;
- this.txFeeAsLong = builder.txFeeAsLong;
- this.takerFeeAsLong = builder.takerFeeAsLong;
- this.takerFeeTxId = builder.takerFeeTxId;
- this.depositTxId = builder.depositTxId;
- this.payoutTxId = builder.payoutTxId;
- this.tradeAmountAsLong = builder.tradeAmountAsLong;
- this.tradePrice = builder.tradePrice;
- this.tradeVolume = builder.tradeVolume;
- this.tradingPeerNodeAddress = builder.tradingPeerNodeAddress;
- this.state = builder.state;
- this.phase = builder.phase;
- this.tradePeriodState = builder.tradePeriodState;
- this.isDepositPublished = builder.isDepositPublished;
- this.isDepositConfirmed = builder.isDepositConfirmed;
- this.isFiatSent = builder.isFiatSent;
- this.isFiatReceived = builder.isFiatReceived;
- this.isPayoutPublished = builder.isPayoutPublished;
- this.isWithdrawn = builder.isWithdrawn;
- this.contractAsJson = builder.contractAsJson;
- this.contract = builder.contract;
+ public static TradeInfo toNewTradeInfo(BsqSwapTrade trade, String role) {
+ // Always called by the taker, isMyOffer=false.
+ return toTradeInfo(trade, role, false, 0);
}
public static TradeInfo toNewTradeInfo(Trade trade) {
+ // Always called by the taker, isMyOffer=false.
return toTradeInfo(trade, null, false);
}
- public static TradeInfo toTradeInfo(Trade trade, String role, boolean isMyOffer) {
+ public static TradeInfo toTradeInfo(TradeModel tradeModel, String role, boolean isMyOffer) {
+ if (tradeModel instanceof Trade)
+ return toTradeInfo((Trade) tradeModel, role, isMyOffer);
+ else if (tradeModel instanceof BsqSwapTrade)
+ return toTradeInfo(tradeModel, role, isMyOffer);
+ else
+ throw new IllegalStateException("unsupported trade type: " + tradeModel.getClass().getSimpleName());
+ }
+
+ public static TradeInfo toTradeInfo(BsqSwapTrade bsqSwapTrade,
+ String role,
+ boolean isMyOffer,
+ int numConfirmations) {
+ OfferInfo offerInfo = isMyOffer ? toMyOfferInfo(bsqSwapTrade.getOffer()) : toOfferInfo(bsqSwapTrade.getOffer());
+ TradeInfo tradeInfo = new TradeInfoV1Builder()
+ .withOffer(offerInfo)
+ .withTradeId(bsqSwapTrade.getId())
+ .withShortId(bsqSwapTrade.getShortId())
+ .withDate(bsqSwapTrade.getDate().getTime())
+ .withRole(role == null ? "" : role)
+ .withIsCurrencyForTakerFeeBtc(false) // BSQ Swap fees always paid in BSQ.
+ .withTxFeeAsLong(bsqSwapTrade.getTxFee().value)
+ .withTakerFeeAsLong(bsqSwapTrade.getTakerFeeAsLong())
+ // N/A: .withTakerFeeTxId(""), .withDepositTxId(""), .withPayoutTxId("")
+ .withTradeAmountAsLong(bsqSwapTrade.getAmountAsLong())
+ .withTradePrice(bsqSwapTrade.getPrice().getValue())
+ .withTradeVolume(bsqSwapTrade.getVolume() == null ? 0 : bsqSwapTrade.getVolume().getValue())
+ .withTradingPeerNodeAddress(requireNonNull(bsqSwapTrade.getTradingPeerNodeAddress().getFullAddress()))
+ .withState(bsqSwapTrade.getTradeState().name())
+ .withPhase(bsqSwapTrade.getTradePhase().name())
+ // N/A: .withTradePeriodState(""), .withIsDepositPublished(false), .withIsDepositConfirmed(false)
+ // N/A: .withIsFiatSent(false), .withIsFiatReceived(false), .withIsPayoutPublished(false)
+ // N/A: .withIsWithdrawn(false), .withContractAsJson(""), .withContract(null)
+ .build();
+ tradeInfo.bsqSwapTradeInfo = toBsqSwapTradeInfo(bsqSwapTrade, isMyOffer, numConfirmations);
+ return tradeInfo;
+ }
+
+ private static TradeInfo toTradeInfo(Trade trade, String role, boolean isMyOffer) {
ContractInfo contractInfo;
if (trade.getContract() != null) {
Contract contract = trade.getContract();
@@ -118,9 +170,8 @@ public static TradeInfo toTradeInfo(Trade trade, String role, boolean isMyOffer)
contractInfo = ContractInfo.emptyContract.get();
}
- OfferInfo offerInfo = toOfferInfo(trade.getOffer());
- offerInfo.setIsMyOffer(isMyOffer);
- return new TradeInfoBuilder()
+ OfferInfo offerInfo = isMyOffer ? toMyOfferInfo(trade.getOffer()) : toOfferInfo(trade.getOffer());
+ return new TradeInfoV1Builder()
.withOffer(offerInfo)
.withTradeId(trade.getId())
.withShortId(trade.getShortId())
@@ -129,15 +180,13 @@ public static TradeInfo toTradeInfo(Trade trade, String role, boolean isMyOffer)
.withIsCurrencyForTakerFeeBtc(trade.isCurrencyForTakerFeeBtc())
.withTxFeeAsLong(trade.getTradeTxFeeAsLong())
.withTakerFeeAsLong(trade.getTakerFeeAsLong())
- .withTakerFeeAsLong(trade.getTakerFeeAsLong())
.withTakerFeeTxId(trade.getTakerFeeTxId())
.withDepositTxId(trade.getDepositTxId())
.withPayoutTxId(trade.getPayoutTxId())
.withTradeAmountAsLong(trade.getAmountAsLong())
.withTradePrice(trade.getPrice().getValue())
.withTradeVolume(trade.getVolume() == null ? 0 : trade.getVolume().getValue())
- .withTradingPeerNodeAddress(Objects.requireNonNull(
- trade.getTradingPeerNodeAddress()).getHostNameWithoutPostFix())
+ .withTradingPeerNodeAddress(requireNonNull(trade.getTradingPeerNodeAddress().getFullAddress()))
.withState(trade.getTradeState().name())
.withPhase(trade.getTradePhase().name())
.withTradePeriodState(trade.getTradePeriodState().name())
@@ -158,38 +207,45 @@ public static TradeInfo toTradeInfo(Trade trade, String role, boolean isMyOffer)
@Override
public bisq.proto.grpc.TradeInfo toProtoMessage() {
- return bisq.proto.grpc.TradeInfo.newBuilder()
- .setOffer(offer.toProtoMessage())
- .setTradeId(tradeId)
- .setShortId(shortId)
- .setDate(date)
- .setRole(role)
- .setIsCurrencyForTakerFeeBtc(isCurrencyForTakerFeeBtc)
- .setTxFeeAsLong(txFeeAsLong)
- .setTakerFeeAsLong(takerFeeAsLong)
- .setTakerFeeTxId(takerFeeTxId == null ? "" : takerFeeTxId)
- .setDepositTxId(depositTxId == null ? "" : depositTxId)
- .setPayoutTxId(payoutTxId == null ? "" : payoutTxId)
- .setTradeAmountAsLong(tradeAmountAsLong)
- .setTradePrice(tradePrice)
- .setTradeVolume(tradeVolume)
- .setTradingPeerNodeAddress(tradingPeerNodeAddress)
- .setState(state)
- .setPhase(phase)
- .setTradePeriodState(tradePeriodState)
- .setIsDepositPublished(isDepositPublished)
- .setIsDepositConfirmed(isDepositConfirmed)
- .setIsFiatSent(isFiatSent)
- .setIsFiatReceived(isFiatReceived)
- .setIsPayoutPublished(isPayoutPublished)
- .setIsWithdrawn(isWithdrawn)
- .setContractAsJson(contractAsJson == null ? "" : contractAsJson)
- .setContract(contract.toProtoMessage())
- .build();
+ var protoBuilder =
+ bisq.proto.grpc.TradeInfo.newBuilder()
+ .setOffer(offer.toProtoMessage())
+ .setTradeId(tradeId)
+ .setShortId(shortId)
+ .setDate(date)
+ .setRole(role)
+ .setIsCurrencyForTakerFeeBtc(isCurrencyForTakerFeeBtc)
+ .setTxFeeAsLong(txFeeAsLong)
+ .setTakerFeeAsLong(takerFeeAsLong)
+ .setTakerFeeTxId(takerFeeTxId == null ? "" : takerFeeTxId)
+ .setDepositTxId(depositTxId == null ? "" : depositTxId)
+ .setPayoutTxId(payoutTxId == null ? "" : payoutTxId)
+ .setTradeAmountAsLong(tradeAmountAsLong)
+ .setTradePrice(tradePrice)
+ .setTradeVolume(tradeVolume)
+ .setTradingPeerNodeAddress(tradingPeerNodeAddress)
+ .setState(state == null ? "" : state)
+ .setPhase(phase == null ? "" : phase)
+ .setTradePeriodState(tradePeriodState == null ? "" : tradePeriodState)
+ .setIsDepositPublished(isDepositPublished)
+ .setIsDepositConfirmed(isDepositConfirmed)
+ .setIsFiatSent(isFiatSent)
+ .setIsFiatReceived(isFiatReceived)
+ .setIsPayoutPublished(isPayoutPublished)
+ .setIsWithdrawn(isWithdrawn);
+
+ if (offer.isBsqSwapOffer()) {
+ protoBuilder.setBsqSwapTradeInfo(bsqSwapTradeInfo.toProtoMessage());
+ } else {
+ protoBuilder.setContractAsJson(contractAsJson == null ? "" : contractAsJson);
+ protoBuilder.setContract(contract.toProtoMessage());
+ }
+
+ return protoBuilder.build();
}
public static TradeInfo fromProto(bisq.proto.grpc.TradeInfo proto) {
- return new TradeInfoBuilder()
+ var tradeInfo = new TradeInfoV1Builder()
.withOffer(OfferInfo.fromProto(proto.getOffer()))
.withTradeId(proto.getTradeId())
.withShortId(proto.getShortId())
@@ -217,175 +273,11 @@ public static TradeInfo fromProto(bisq.proto.grpc.TradeInfo proto) {
.withContractAsJson(proto.getContractAsJson())
.withContract((ContractInfo.fromProto(proto.getContract())))
.build();
- }
-
- /*
- * TradeInfoBuilder helps avoid bungling use of a large TradeInfo constructor
- * argument list. If consecutive argument values of the same type are not
- * ordered correctly, the compiler won't complain but the resulting bugs could
- * be hard to find and fix.
- */
- public static class TradeInfoBuilder {
- private OfferInfo offer;
- private String tradeId;
- private String shortId;
- private long date;
- private String role;
- private boolean isCurrencyForTakerFeeBtc;
- private long txFeeAsLong;
- private long takerFeeAsLong;
- private String takerFeeTxId;
- private String depositTxId;
- private String payoutTxId;
- private long tradeAmountAsLong;
- private long tradePrice;
- private long tradeVolume;
- private String tradingPeerNodeAddress;
- private String state;
- private String phase;
- private String tradePeriodState;
- private boolean isDepositPublished;
- private boolean isDepositConfirmed;
- private boolean isFiatSent;
- private boolean isFiatReceived;
- private boolean isPayoutPublished;
- private boolean isWithdrawn;
- private String contractAsJson;
- private ContractInfo contract;
-
- public TradeInfoBuilder withOffer(OfferInfo offer) {
- this.offer = offer;
- return this;
- }
-
- public TradeInfoBuilder withTradeId(String tradeId) {
- this.tradeId = tradeId;
- return this;
- }
-
- public TradeInfoBuilder withShortId(String shortId) {
- this.shortId = shortId;
- return this;
- }
-
- public TradeInfoBuilder withDate(long date) {
- this.date = date;
- return this;
- }
-
- public TradeInfoBuilder withRole(String role) {
- this.role = role;
- return this;
- }
-
- public TradeInfoBuilder withIsCurrencyForTakerFeeBtc(boolean isCurrencyForTakerFeeBtc) {
- this.isCurrencyForTakerFeeBtc = isCurrencyForTakerFeeBtc;
- return this;
- }
-
- public TradeInfoBuilder withTxFeeAsLong(long txFeeAsLong) {
- this.txFeeAsLong = txFeeAsLong;
- return this;
- }
-
- public TradeInfoBuilder withTakerFeeAsLong(long takerFeeAsLong) {
- this.takerFeeAsLong = takerFeeAsLong;
- return this;
- }
-
- public TradeInfoBuilder withTakerFeeTxId(String takerFeeTxId) {
- this.takerFeeTxId = takerFeeTxId;
- return this;
- }
- public TradeInfoBuilder withDepositTxId(String depositTxId) {
- this.depositTxId = depositTxId;
- return this;
- }
-
- public TradeInfoBuilder withPayoutTxId(String payoutTxId) {
- this.payoutTxId = payoutTxId;
- return this;
- }
-
- public TradeInfoBuilder withTradeAmountAsLong(long tradeAmountAsLong) {
- this.tradeAmountAsLong = tradeAmountAsLong;
- return this;
- }
-
- public TradeInfoBuilder withTradePrice(long tradePrice) {
- this.tradePrice = tradePrice;
- return this;
- }
-
- public TradeInfoBuilder withTradeVolume(long tradeVolume) {
- this.tradeVolume = tradeVolume;
- return this;
- }
-
- public TradeInfoBuilder withTradePeriodState(String tradePeriodState) {
- this.tradePeriodState = tradePeriodState;
- return this;
- }
-
- public TradeInfoBuilder withState(String state) {
- this.state = state;
- return this;
- }
-
- public TradeInfoBuilder withPhase(String phase) {
- this.phase = phase;
- return this;
- }
-
- public TradeInfoBuilder withTradingPeerNodeAddress(String tradingPeerNodeAddress) {
- this.tradingPeerNodeAddress = tradingPeerNodeAddress;
- return this;
- }
+ if (proto.getOffer().getIsBsqSwapOffer())
+ tradeInfo.bsqSwapTradeInfo = BsqSwapTradeInfo.fromProto(proto.getBsqSwapTradeInfo());
- public TradeInfoBuilder withIsDepositPublished(boolean isDepositPublished) {
- this.isDepositPublished = isDepositPublished;
- return this;
- }
-
- public TradeInfoBuilder withIsDepositConfirmed(boolean isDepositConfirmed) {
- this.isDepositConfirmed = isDepositConfirmed;
- return this;
- }
-
- public TradeInfoBuilder withIsFiatSent(boolean isFiatSent) {
- this.isFiatSent = isFiatSent;
- return this;
- }
-
- public TradeInfoBuilder withIsFiatReceived(boolean isFiatReceived) {
- this.isFiatReceived = isFiatReceived;
- return this;
- }
-
- public TradeInfoBuilder withIsPayoutPublished(boolean isPayoutPublished) {
- this.isPayoutPublished = isPayoutPublished;
- return this;
- }
-
- public TradeInfoBuilder withIsWithdrawn(boolean isWithdrawn) {
- this.isWithdrawn = isWithdrawn;
- return this;
- }
-
- public TradeInfoBuilder withContractAsJson(String contractAsJson) {
- this.contractAsJson = contractAsJson;
- return this;
- }
-
- public TradeInfoBuilder withContract(ContractInfo contract) {
- this.contract = contract;
- return this;
- }
-
- public TradeInfo build() {
- return new TradeInfo(this);
- }
+ return tradeInfo;
}
@Override
@@ -417,6 +309,7 @@ public String toString() {
", offer=" + offer + "\n" +
", contractAsJson=" + contractAsJson + "\n" +
", contract=" + contract + "\n" +
+ ", bsqSwapTradeInfo=" + bsqSwapTradeInfo + "\n" +
'}';
}
}
diff --git a/core/src/main/java/bisq/core/api/model/TxInfo.java b/core/src/main/java/bisq/core/api/model/TxInfo.java
index 3bd937c96e5..54023b2ec3a 100644
--- a/core/src/main/java/bisq/core/api/model/TxInfo.java
+++ b/core/src/main/java/bisq/core/api/model/TxInfo.java
@@ -46,7 +46,7 @@ public class TxInfo implements Payload {
private final boolean isPending;
private final String memo;
- public TxInfo(TxInfoBuilder builder) {
+ public TxInfo(Builder builder) {
this.txId = builder.txId;
this.inputSum = builder.inputSum;
this.outputSum = builder.outputSum;
@@ -61,7 +61,7 @@ public static TxInfo toTxInfo(Transaction transaction) {
throw new IllegalStateException("server created a null transaction");
if (transaction.getFee() != null)
- return new TxInfoBuilder()
+ return new Builder()
.withTxId(transaction.getTxId().toString())
.withInputSum(transaction.getInputSum().value)
.withOutputSum(transaction.getOutputSum().value)
@@ -71,7 +71,7 @@ public static TxInfo toTxInfo(Transaction transaction) {
.withMemo(transaction.getMemo())
.build();
else
- return new TxInfoBuilder()
+ return new Builder()
.withTxId(transaction.getTxId().toString())
.withInputSum(transaction.getInputSum().value)
.withOutputSum(transaction.getOutputSum().value)
@@ -101,7 +101,7 @@ public bisq.proto.grpc.TxInfo toProtoMessage() {
@SuppressWarnings("unused")
public static TxInfo fromProto(bisq.proto.grpc.TxInfo proto) {
- return new TxInfoBuilder()
+ return new Builder()
.withTxId(proto.getTxId())
.withInputSum(proto.getInputSum())
.withOutputSum(proto.getOutputSum())
@@ -112,7 +112,7 @@ public static TxInfo fromProto(bisq.proto.grpc.TxInfo proto) {
.build();
}
- public static class TxInfoBuilder {
+ private static class Builder {
private String txId;
private long inputSum;
private long outputSum;
@@ -121,37 +121,37 @@ public static class TxInfoBuilder {
private boolean isPending;
private String memo;
- public TxInfoBuilder withTxId(String txId) {
+ public Builder withTxId(String txId) {
this.txId = txId;
return this;
}
- public TxInfoBuilder withInputSum(long inputSum) {
+ public Builder withInputSum(long inputSum) {
this.inputSum = inputSum;
return this;
}
- public TxInfoBuilder withOutputSum(long outputSum) {
+ public Builder withOutputSum(long outputSum) {
this.outputSum = outputSum;
return this;
}
- public TxInfoBuilder withFee(long fee) {
+ public Builder withFee(long fee) {
this.fee = fee;
return this;
}
- public TxInfoBuilder withSize(int size) {
+ public Builder withSize(int size) {
this.size = size;
return this;
}
- public TxInfoBuilder withIsPending(boolean isPending) {
+ public Builder withIsPending(boolean isPending) {
this.isPending = isPending;
return this;
}
- public TxInfoBuilder withMemo(String memo) {
+ public Builder withMemo(String memo) {
this.memo = memo;
return this;
}
diff --git a/core/src/main/java/bisq/core/api/model/builder/BsqSwapTradeInfoBuilder.java b/core/src/main/java/bisq/core/api/model/builder/BsqSwapTradeInfoBuilder.java
new file mode 100644
index 00000000000..3ae01d4ea8c
--- /dev/null
+++ b/core/src/main/java/bisq/core/api/model/builder/BsqSwapTradeInfoBuilder.java
@@ -0,0 +1,113 @@
+/*
+ * 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 .
+ */
+
+package bisq.core.api.model.builder;
+
+import bisq.core.api.model.BsqSwapTradeInfo;
+
+import lombok.Getter;
+
+/**
+ * Proto wrapper for BSQ swap protocol details not common to Bisq v1
+ * trade protocol details.
+ *
+ * This builder helps avoid bungling use of a large BsqSwapTradeInfo constructor
+ * argument list. If consecutive argument values of the same type are not
+ * ordered correctly, the compiler won't complain but the resulting bugs could
+ * be hard to find and fix.
+ */
+@Getter
+public final class BsqSwapTradeInfoBuilder {
+
+ private String txId;
+ private long bsqTradeAmount;
+ private long btcTradeAmount;
+ private long bsqMakerTradeFee;
+ private long bsqTakerTradeFee;
+ private long txFeePerVbyte;
+ private String makerBsqAddress;
+ private String makerBtcAddress;
+ private String takerBsqAddress;
+ private String takerBtcAddress;
+ private long numConfirmations;
+ private String errorMessage;
+
+ public BsqSwapTradeInfoBuilder withTxId(String txId) {
+ this.txId = txId;
+ return this;
+ }
+
+ public BsqSwapTradeInfoBuilder withBsqTradeAmount(long bsqTradeAmount) {
+ this.bsqTradeAmount = bsqTradeAmount;
+ return this;
+ }
+
+ public BsqSwapTradeInfoBuilder withBtcTradeAmount(long btcTradeAmount) {
+ this.btcTradeAmount = btcTradeAmount;
+ return this;
+ }
+
+ public BsqSwapTradeInfoBuilder withBsqMakerTradeFee(long bsqMakerTradeFee) {
+ this.bsqMakerTradeFee = bsqMakerTradeFee;
+ return this;
+ }
+
+ public BsqSwapTradeInfoBuilder withBsqTakerTradeFee(long bsqTakerTradeFee) {
+ this.bsqTakerTradeFee = bsqTakerTradeFee;
+ return this;
+ }
+
+ public BsqSwapTradeInfoBuilder withTxFeePerVbyte(long txFeePerVbyte) {
+ this.txFeePerVbyte = txFeePerVbyte;
+ return this;
+ }
+
+ public BsqSwapTradeInfoBuilder withMakerBsqAddress(String makerBsqAddress) {
+ this.makerBsqAddress = makerBsqAddress;
+ return this;
+ }
+
+ public BsqSwapTradeInfoBuilder withMakerBtcAddress(String makerBtcAddress) {
+ this.makerBtcAddress = makerBtcAddress;
+ return this;
+ }
+
+ public BsqSwapTradeInfoBuilder withTakerBsqAddress(String takerBsqAddress) {
+ this.takerBsqAddress = takerBsqAddress;
+ return this;
+ }
+
+ public BsqSwapTradeInfoBuilder withTakerBtcAddress(String takerBtcAddress) {
+ this.takerBtcAddress = takerBtcAddress;
+ return this;
+ }
+
+ public BsqSwapTradeInfoBuilder withNumConfirmations(long numConfirmations) {
+ this.numConfirmations = numConfirmations;
+ return this;
+ }
+
+ public BsqSwapTradeInfoBuilder withErrorMessage(String errorMessage) {
+ this.errorMessage = errorMessage;
+ return this;
+ }
+
+ public BsqSwapTradeInfo build() {
+ return new BsqSwapTradeInfo(this);
+ }
+}
+
diff --git a/core/src/main/java/bisq/core/api/model/builder/OfferInfoBuilder.java b/core/src/main/java/bisq/core/api/model/builder/OfferInfoBuilder.java
new file mode 100644
index 00000000000..3773b465f72
--- /dev/null
+++ b/core/src/main/java/bisq/core/api/model/builder/OfferInfoBuilder.java
@@ -0,0 +1,223 @@
+/*
+ * 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 .
+ */
+
+package bisq.core.api.model.builder;
+
+import bisq.core.api.model.OfferInfo;
+
+import lombok.Getter;
+
+/*
+ * A builder helps avoid bungling use of a large OfferInfo constructor
+ * argument list. If consecutive argument values of the same type are not
+ * ordered correctly, the compiler won't complain but the resulting bugs could
+ * be hard to find and fix.
+ */
+@Getter
+public final class OfferInfoBuilder {
+
+ private String id;
+ private String direction;
+ private long price;
+ private boolean useMarketBasedPrice;
+ private double marketPriceMargin;
+ private long amount;
+ private long minAmount;
+ private long volume;
+ private long minVolume;
+ private long txFee;
+ private long makerFee;
+ private String offerFeePaymentTxId;
+ private long buyerSecurityDeposit;
+ private long sellerSecurityDeposit;
+ private long triggerPrice;
+ private boolean isCurrencyForMakerFeeBtc;
+ private String paymentAccountId;
+ private String paymentMethodId;
+ private String paymentMethodShortName;
+ private String baseCurrencyCode;
+ private String counterCurrencyCode;
+ private long date;
+ private String state;
+ private boolean isActivated;
+ private boolean isMyOffer;
+ private boolean isMyPendingOffer;
+ private boolean isBsqSwapOffer;
+ private String ownerNodeAddress;
+ private String pubKeyRing;
+ private String versionNumber;
+ private int protocolVersion;
+
+ public OfferInfoBuilder withId(String id) {
+ this.id = id;
+ return this;
+ }
+
+ public OfferInfoBuilder withDirection(String direction) {
+ this.direction = direction;
+ return this;
+ }
+
+ public OfferInfoBuilder withPrice(long price) {
+ this.price = price;
+ return this;
+ }
+
+ public OfferInfoBuilder withUseMarketBasedPrice(boolean useMarketBasedPrice) {
+ this.useMarketBasedPrice = useMarketBasedPrice;
+ return this;
+ }
+
+ public OfferInfoBuilder withMarketPriceMargin(double useMarketBasedPrice) {
+ this.marketPriceMargin = useMarketBasedPrice;
+ return this;
+ }
+
+ public OfferInfoBuilder withAmount(long amount) {
+ this.amount = amount;
+ return this;
+ }
+
+ public OfferInfoBuilder withMinAmount(long minAmount) {
+ this.minAmount = minAmount;
+ return this;
+ }
+
+ public OfferInfoBuilder withVolume(long volume) {
+ this.volume = volume;
+ return this;
+ }
+
+ public OfferInfoBuilder withMinVolume(long minVolume) {
+ this.minVolume = minVolume;
+ return this;
+ }
+
+ public OfferInfoBuilder withTxFee(long txFee) {
+ this.txFee = txFee;
+ return this;
+ }
+
+ public OfferInfoBuilder withMakerFee(long makerFee) {
+ this.makerFee = makerFee;
+ return this;
+ }
+
+ public OfferInfoBuilder withOfferFeePaymentTxId(String offerFeePaymentTxId) {
+ this.offerFeePaymentTxId = offerFeePaymentTxId;
+ return this;
+ }
+
+ public OfferInfoBuilder withBuyerSecurityDeposit(long buyerSecurityDeposit) {
+ this.buyerSecurityDeposit = buyerSecurityDeposit;
+ return this;
+ }
+
+ public OfferInfoBuilder withSellerSecurityDeposit(long sellerSecurityDeposit) {
+ this.sellerSecurityDeposit = sellerSecurityDeposit;
+ return this;
+ }
+
+ public OfferInfoBuilder withTriggerPrice(long triggerPrice) {
+ this.triggerPrice = triggerPrice;
+ return this;
+ }
+
+ public OfferInfoBuilder withIsCurrencyForMakerFeeBtc(boolean isCurrencyForMakerFeeBtc) {
+ this.isCurrencyForMakerFeeBtc = isCurrencyForMakerFeeBtc;
+ return this;
+ }
+
+ public OfferInfoBuilder withPaymentAccountId(String paymentAccountId) {
+ this.paymentAccountId = paymentAccountId;
+ return this;
+ }
+
+ public OfferInfoBuilder withPaymentMethodId(String paymentMethodId) {
+ this.paymentMethodId = paymentMethodId;
+ return this;
+ }
+
+ public OfferInfoBuilder withPaymentMethodShortName(String paymentMethodShortName) {
+ this.paymentMethodShortName = paymentMethodShortName;
+ return this;
+ }
+
+ public OfferInfoBuilder withBaseCurrencyCode(String baseCurrencyCode) {
+ this.baseCurrencyCode = baseCurrencyCode;
+ return this;
+ }
+
+ public OfferInfoBuilder withCounterCurrencyCode(String counterCurrencyCode) {
+ this.counterCurrencyCode = counterCurrencyCode;
+ return this;
+ }
+
+ public OfferInfoBuilder withDate(long date) {
+ this.date = date;
+ return this;
+ }
+
+ public OfferInfoBuilder withState(String state) {
+ this.state = state;
+ return this;
+ }
+
+ public OfferInfoBuilder withIsActivated(boolean isActivated) {
+ this.isActivated = isActivated;
+ return this;
+ }
+
+ public OfferInfoBuilder withIsMyOffer(boolean isMyOffer) {
+ this.isMyOffer = isMyOffer;
+ return this;
+ }
+
+ public OfferInfoBuilder withIsMyPendingOffer(boolean isMyPendingOffer) {
+ this.isMyPendingOffer = isMyPendingOffer;
+ return this;
+ }
+
+ public OfferInfoBuilder withIsBsqSwapOffer(boolean isBsqSwapOffer) {
+ this.isBsqSwapOffer = isBsqSwapOffer;
+ return this;
+ }
+
+ public OfferInfoBuilder withOwnerNodeAddress(String ownerNodeAddress) {
+ this.ownerNodeAddress = ownerNodeAddress;
+ return this;
+ }
+
+ public OfferInfoBuilder withPubKeyRing(String pubKeyRing) {
+ this.pubKeyRing = pubKeyRing;
+ return this;
+ }
+
+ public OfferInfoBuilder withVersionNumber(String versionNumber) {
+ this.versionNumber = versionNumber;
+ return this;
+ }
+
+ public OfferInfoBuilder withProtocolVersion(int protocolVersion) {
+ this.protocolVersion = protocolVersion;
+ return this;
+ }
+
+ public OfferInfo build() {
+ return new OfferInfo(this);
+ }
+}
diff --git a/core/src/main/java/bisq/core/api/model/builder/TradeInfoV1Builder.java b/core/src/main/java/bisq/core/api/model/builder/TradeInfoV1Builder.java
new file mode 100644
index 00000000000..2bff2254a85
--- /dev/null
+++ b/core/src/main/java/bisq/core/api/model/builder/TradeInfoV1Builder.java
@@ -0,0 +1,195 @@
+/*
+ * 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 .
+ */
+
+package bisq.core.api.model.builder;
+
+import bisq.core.api.model.ContractInfo;
+import bisq.core.api.model.OfferInfo;
+import bisq.core.api.model.TradeInfo;
+
+import lombok.Getter;
+
+/**
+ * A builder helps avoid bungling use of a large TradeInfo constructor
+ * argument list. If consecutive argument values of the same type are not
+ * ordered correctly, the compiler won't complain but the resulting bugs could
+ * be hard to find and fix.
+ */
+@Getter
+public final class TradeInfoV1Builder {
+
+ private OfferInfo offer;
+ private String tradeId;
+ private String shortId;
+ private long date;
+ private String role;
+ private boolean isCurrencyForTakerFeeBtc;
+ private long txFeeAsLong;
+ private long takerFeeAsLong;
+ private String takerFeeTxId;
+ private String depositTxId;
+ private String payoutTxId;
+ private long tradeAmountAsLong;
+ private long tradePrice;
+ private long tradeVolume;
+ private String tradingPeerNodeAddress;
+ private String state;
+ private String phase;
+ private String tradePeriodState;
+ private boolean isDepositPublished;
+ private boolean isDepositConfirmed;
+ private boolean isFiatSent;
+ private boolean isFiatReceived;
+ private boolean isPayoutPublished;
+ private boolean isWithdrawn;
+ private String contractAsJson;
+ private ContractInfo contract;
+
+ public TradeInfoV1Builder withOffer(OfferInfo offer) {
+ this.offer = offer;
+ return this;
+ }
+
+ public TradeInfoV1Builder withTradeId(String tradeId) {
+ this.tradeId = tradeId;
+ return this;
+ }
+
+ public TradeInfoV1Builder withShortId(String shortId) {
+ this.shortId = shortId;
+ return this;
+ }
+
+ public TradeInfoV1Builder withDate(long date) {
+ this.date = date;
+ return this;
+ }
+
+ public TradeInfoV1Builder withRole(String role) {
+ this.role = role;
+ return this;
+ }
+
+ public TradeInfoV1Builder withIsCurrencyForTakerFeeBtc(boolean isCurrencyForTakerFeeBtc) {
+ this.isCurrencyForTakerFeeBtc = isCurrencyForTakerFeeBtc;
+ return this;
+ }
+
+ public TradeInfoV1Builder withTxFeeAsLong(long txFeeAsLong) {
+ this.txFeeAsLong = txFeeAsLong;
+ return this;
+ }
+
+ public TradeInfoV1Builder withTakerFeeAsLong(long takerFeeAsLong) {
+ this.takerFeeAsLong = takerFeeAsLong;
+ return this;
+ }
+
+ public TradeInfoV1Builder withTakerFeeTxId(String takerFeeTxId) {
+ this.takerFeeTxId = takerFeeTxId;
+ return this;
+ }
+
+ public TradeInfoV1Builder withDepositTxId(String depositTxId) {
+ this.depositTxId = depositTxId;
+ return this;
+ }
+
+ public TradeInfoV1Builder withPayoutTxId(String payoutTxId) {
+ this.payoutTxId = payoutTxId;
+ return this;
+ }
+
+ public TradeInfoV1Builder withTradeAmountAsLong(long tradeAmountAsLong) {
+ this.tradeAmountAsLong = tradeAmountAsLong;
+ return this;
+ }
+
+ public TradeInfoV1Builder withTradePrice(long tradePrice) {
+ this.tradePrice = tradePrice;
+ return this;
+ }
+
+ public TradeInfoV1Builder withTradeVolume(long tradeVolume) {
+ this.tradeVolume = tradeVolume;
+ return this;
+ }
+
+ public TradeInfoV1Builder withTradePeriodState(String tradePeriodState) {
+ this.tradePeriodState = tradePeriodState;
+ return this;
+ }
+
+ public TradeInfoV1Builder withState(String state) {
+ this.state = state;
+ return this;
+ }
+
+ public TradeInfoV1Builder withPhase(String phase) {
+ this.phase = phase;
+ return this;
+ }
+
+ public TradeInfoV1Builder withTradingPeerNodeAddress(String tradingPeerNodeAddress) {
+ this.tradingPeerNodeAddress = tradingPeerNodeAddress;
+ return this;
+ }
+
+ public TradeInfoV1Builder withIsDepositPublished(boolean isDepositPublished) {
+ this.isDepositPublished = isDepositPublished;
+ return this;
+ }
+
+ public TradeInfoV1Builder withIsDepositConfirmed(boolean isDepositConfirmed) {
+ this.isDepositConfirmed = isDepositConfirmed;
+ return this;
+ }
+
+ public TradeInfoV1Builder withIsFiatSent(boolean isFiatSent) {
+ this.isFiatSent = isFiatSent;
+ return this;
+ }
+
+ public TradeInfoV1Builder withIsFiatReceived(boolean isFiatReceived) {
+ this.isFiatReceived = isFiatReceived;
+ return this;
+ }
+
+ public TradeInfoV1Builder withIsPayoutPublished(boolean isPayoutPublished) {
+ this.isPayoutPublished = isPayoutPublished;
+ return this;
+ }
+
+ public TradeInfoV1Builder withIsWithdrawn(boolean isWithdrawn) {
+ this.isWithdrawn = isWithdrawn;
+ return this;
+ }
+
+ public TradeInfoV1Builder withContractAsJson(String contractAsJson) {
+ this.contractAsJson = contractAsJson;
+ return this;
+ }
+
+ public TradeInfoV1Builder withContract(ContractInfo contract) {
+ this.contract = contract;
+ return this;
+ }
+
+ public TradeInfo build() {
+ return new TradeInfo(this);
+ }
+}
diff --git a/core/src/main/java/bisq/core/offer/OfferUtil.java b/core/src/main/java/bisq/core/offer/OfferUtil.java
index c676c57bbdc..d13d45742f7 100644
--- a/core/src/main/java/bisq/core/offer/OfferUtil.java
+++ b/core/src/main/java/bisq/core/offer/OfferUtil.java
@@ -488,6 +488,14 @@ private Optional getFeeInUserFiatCurrency(Coin makerFee,
}
}
+ public static boolean isFiatOffer(Offer offer) {
+ return offer.getBaseCurrencyCode().equals("BTC") && !offer.isBsqSwapOffer();
+ }
+
+ public static boolean isAltcoinOffer(Offer offer) {
+ return offer.getCounterCurrencyCode().equals("BTC") && !offer.isBsqSwapOffer();
+ }
+
public static Optional getInvalidMakerFeeTxErrorMessage(Offer offer, BtcWalletService btcWalletService) {
String offerFeePaymentTxId = offer.getOfferFeePaymentTxId();
if (offerFeePaymentTxId == null) {
diff --git a/core/src/main/java/bisq/core/trade/bisq_v1/TradeUtil.java b/core/src/main/java/bisq/core/trade/bisq_v1/TradeUtil.java
index 3f99e7dea9b..9d8212a060b 100644
--- a/core/src/main/java/bisq/core/trade/bisq_v1/TradeUtil.java
+++ b/core/src/main/java/bisq/core/trade/bisq_v1/TradeUtil.java
@@ -25,6 +25,7 @@
import bisq.core.trade.model.TradeModel;
import bisq.core.trade.model.bisq_v1.Contract;
import bisq.core.trade.model.bisq_v1.Trade;
+import bisq.core.trade.model.bsq_swap.BsqSwapTrade;
import bisq.network.p2p.NodeAddress;
@@ -57,6 +58,8 @@
@Singleton
public class TradeUtil {
+ // TODO change non-state dependent instance methods to static methods.
+
private final BtcWalletService btcWalletService;
private final KeyRing keyRing;
@@ -203,6 +206,24 @@ public String getRole(Trade trade) {
offer.getCurrencyCode());
}
+ /**
+ * Returns a string describing a trader's role for a given bsq swap.
+ * @param trade BsqSwapTrade
+ * @return String describing a trader's role for a given bsq swap
+ */
+ public String getRole(BsqSwapTrade trade) {
+ Offer offer = trade.getOffer();
+ if (offer == null)
+ throw new IllegalStateException(
+ format("could not get role because no offer was found for bsq swap '%s'",
+ trade.getShortId()));
+
+ KeyRing keyRing = trade.getBsqSwapProtocolModel().getKeyRing();
+ return getRole(offer.isBuyOffer(),
+ offer.isMyOffer(keyRing),
+ offer.getCurrencyCode());
+ }
+
/**
* Returns a string describing a trader's role.
*
diff --git a/core/src/main/java/bisq/core/trade/protocol/bsq_swap/model/BsqSwapProtocolModel.java b/core/src/main/java/bisq/core/trade/protocol/bsq_swap/model/BsqSwapProtocolModel.java
index bdf5dd88b2c..47b09d10b45 100644
--- a/core/src/main/java/bisq/core/trade/protocol/bsq_swap/model/BsqSwapProtocolModel.java
+++ b/core/src/main/java/bisq/core/trade/protocol/bsq_swap/model/BsqSwapProtocolModel.java
@@ -69,6 +69,7 @@ public class BsqSwapProtocolModel implements ProtocolModel {
transient private Offer offer;
@Setter
transient private TradeMessage tradeMessage;
+ // TODO rename tradingPeerNodeAddress ?
@Nullable
@Setter
transient private NodeAddress tempTradingPeerNodeAddress;
diff --git a/core/src/main/resources/help/createoffer-help.txt b/core/src/main/resources/help/createoffer-help.txt
index 38ec0fd8daf..3dfd2b1eae2 100644
--- a/core/src/main/resources/help/createoffer-help.txt
+++ b/core/src/main/resources/help/createoffer-help.txt
@@ -7,54 +7,76 @@ createoffer - create offer to buy or sell BTC
SYNOPSIS
--------
createoffer
- --payment-account=
- --direction=
- --currency-code=
- --market-price-margin= | --fixed-price=
--amount=
--min-amount=
+ --currency-code=
+ --direction=
+ --fixed-price= | --market-price-margin=
+ --payment-account=
--security-deposit=
+ --swap=
[--fee-currency=]
DESCRIPTION
-----------
-Create and place an offer to buy or sell BTC using a fiat account.
+Create and place an offer to buy or sell BTC. There are two types of offers.
+
+ BSQ swap offers
+
+ The createoffer command requires the swap, amount [, optional min-amount], direction,
+ and fixed-price parameters, where --swap=true and the user's wallet contains sufficient
+ BTC and/or BSQ to cover the trade amount and maker fee.
+
+ Version 1 protocol fiat and BSQ offers
+
+ The createoffer command requires the payment-account, amount [,optional min-amount],
+ currency-code, direction, fixed-price or market-price-margin, and security-deposit parameters.
+ The fee-currency parameter can be optionally used to pay the taker fee in BSQ.
OPTIONS
-------
---payment-account
- The ID of the fiat payment account used to send or receive funds during the trade.
+--amount
+ The amount of BTC to buy or sell, e.g., 0.125.
---direction
- The direction of the trade (BUY or SELL).
+--min-amount
+ The minimum amount of BTC to buy or sell, e.g., 0.006.
+ If --min-amount is not present, it defaults to the --amount value.
--currency-code
- The three letter code for the fiat used to buy or sell BTC, e.g., EUR, USD, BRL, ...
+ The three-letter code for the currency used to buy or sell BTC, e.g., BSQ, EUR, USD, BRL, ...
---market-price-margin
- The % above or below market BTC price, e.g., 1.00 (1%).
- If --market-price-margin is not present, --fixed-price must be.
+--direction
+ The direction of the trade (BUY or SELL).
+
+--fee-currency
+ The wallet currency used to pay the Bisq trade maker fee (BSQ|BTC). Default is BTC
--fixed-price
The fixed BTC price in fiat used to buy or sell BTC, e.g., 34000 (USD).
If --fixed-price is not present, --market-price-margin must be.
---amount
- The amount of BTC to buy or sell, e.g., 0.125.
+--market-price-margin
+ The % above or below market BTC price, e.g., 1.00 (1%).
+ If --market-price-margin is not present, --fixed-price must be.
---min-amount
- The minimum amount of BTC to buy or sell, e.g., 0.006.
- If --min-amount is not present, it defaults to the --amount value.
+--payment-account
+ The ID of the fiat payment account used to send or receive funds during the trade.
--security-deposit
The percentage of the BTC amount being traded for the security deposit, e.g., 60.0 (60%).
---fee-currency
- The wallet currency used to pay the Bisq trade maker fee (BSQ|BTC). Default is BTC
+--swap
+ Flag determining whether the offer is a BSQ swap or version 1 protocol offer. Default is false.
EXAMPLES
--------
+To create a BUY 0.25 BTC with BSQ swap offer at a fixed BSQ price of 0.00005 BSQ per 1 BTC:
+$ ./bisq-cli --password=xyz --port=9998 createoffer --swap=true \
+ --direction=buy \
+ --amount=0.25 \
+ --fixed-price=0.00005
+
To create a BUY 0.125 BTC with EUR offer
at the current market price,
using a payment account with ID 7413d263-225a-4f1b-837a-1e3094dc0d77,
diff --git a/core/src/main/resources/help/takeoffer-help.txt b/core/src/main/resources/help/takeoffer-help.txt
index 1290a008392..f0ecd6f46e6 100644
--- a/core/src/main/resources/help/takeoffer-help.txt
+++ b/core/src/main/resources/help/takeoffer-help.txt
@@ -9,11 +9,22 @@ SYNOPSIS
takeoffer
--offer-id=
--payment-account=
- --fee-currency=
+ [--fee-currency=]
DESCRIPTION
-----------
-Take an existing offer using a matching payment method. The Bisq trade fee can be paid in BSQ or BTC.
+Take an existing offer. There are currently two types offers and trade protocols.
+
+ BSQ swap offers
+
+ The takeoffer command only requires an offer-id parameter, and sufficient BSQ and BTC
+ to cover the trade amount and the taker fee. The trade (swap) will be executed immediately
+ after being successfully taken.
+
+ Version 1 protocol fiat and BSQ offers
+
+ The offer-id and payment-account parameters are required. The fee-currency parameter can
+ be optionally used to pay the taker fee in BSQ.
OPTIONS
-------
@@ -29,6 +40,9 @@ OPTIONS
EXAMPLES
--------
+To take a BSQ swap offer with ID y3a8b2e2-51b6-4f39-b6c1-3ebd52c22aea;
+$ ./bisq-cli --password=xyz --port=9998 takeoffer --offer-id=y3a8b2e2-51b6-4f39-b6c1-3ebd52c22aea
+
To take an offer with ID 83e8b2e2-51b6-4f39-a748-3ebd29c22aea
using a payment account with ID fe20cdbd-22be-4b8a-a4b6-d2608ff09d6e,
and paying the Bisq trading fee in BSQ:
diff --git a/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java b/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java
index bafd4c17d03..edfa09a3d6d 100644
--- a/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java
+++ b/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java
@@ -18,7 +18,6 @@
package bisq.daemon.grpc;
import bisq.core.api.CoreApi;
-import bisq.core.api.model.BsqSwapOfferInfo;
import bisq.core.api.model.OfferInfo;
import bisq.core.offer.Offer;
import bisq.core.offer.OpenOffer;
@@ -33,12 +32,15 @@
import bisq.proto.grpc.EditOfferRequest;
import bisq.proto.grpc.GetBsqSwapOfferReply;
import bisq.proto.grpc.GetBsqSwapOffersReply;
+import bisq.proto.grpc.GetBsqSwapOffersRequest;
import bisq.proto.grpc.GetMyBsqSwapOfferReply;
import bisq.proto.grpc.GetMyBsqSwapOffersReply;
import bisq.proto.grpc.GetMyOfferReply;
import bisq.proto.grpc.GetMyOfferRequest;
import bisq.proto.grpc.GetMyOffersReply;
import bisq.proto.grpc.GetMyOffersRequest;
+import bisq.proto.grpc.GetOfferCategoryReply;
+import bisq.proto.grpc.GetOfferCategoryRequest;
import bisq.proto.grpc.GetOfferReply;
import bisq.proto.grpc.GetOfferRequest;
import bisq.proto.grpc.GetOffersReply;
@@ -56,10 +58,15 @@
import lombok.extern.slf4j.Slf4j;
-import static bisq.core.api.model.BsqSwapOfferInfo.toBsqSwapOfferInfo;
+import static bisq.core.api.model.OfferInfo.toMyPendingOfferInfo;
import static bisq.core.api.model.OfferInfo.toOfferInfo;
-import static bisq.core.api.model.OfferInfo.toPendingOfferInfo;
import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor;
+import static bisq.proto.grpc.GetOfferCategoryReply.OfferCategory;
+import static bisq.proto.grpc.GetOfferCategoryReply.OfferCategory.ALTCOIN;
+import static bisq.proto.grpc.GetOfferCategoryReply.OfferCategory.BSQ_SWAP;
+import static bisq.proto.grpc.GetOfferCategoryReply.OfferCategory.FIAT;
+import static bisq.proto.grpc.GetOfferCategoryReply.OfferCategory.UNKNOWN;
+import static bisq.proto.grpc.GetOfferCategoryReply.newBuilder;
import static bisq.proto.grpc.OffersGrpc.*;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
@@ -81,13 +88,28 @@ public GrpcOffersService(CoreApi coreApi, GrpcExceptionHandler exceptionHandler)
this.exceptionHandler = exceptionHandler;
}
+ @Override
+ public void getOfferCategory(GetOfferCategoryRequest req,
+ StreamObserver responseObserver) {
+ try {
+ OfferCategory category = getOfferCategory(req.getId(), req.getIsMyOffer());
+ var reply = newBuilder()
+ .setOfferCategory(category)
+ .build();
+ responseObserver.onNext(reply);
+ responseObserver.onCompleted();
+ } catch (Throwable cause) {
+ exceptionHandler.handleException(log, cause, responseObserver);
+ }
+ }
+
@Override
public void getBsqSwapOffer(GetOfferRequest req,
StreamObserver responseObserver) {
try {
Offer offer = coreApi.getOffer(req.getId());
var reply = GetBsqSwapOfferReply.newBuilder()
- .setBsqSwapOffer(toBsqSwapOfferInfo(offer).toProtoMessage())
+ .setBsqSwapOffer(toOfferInfo(offer).toProtoMessage())
.build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
@@ -117,7 +139,7 @@ public void getMyBsqSwapOffer(GetMyOfferRequest req,
try {
Offer offer = coreApi.getMyBsqSwapOffer(req.getId());
var reply = GetMyBsqSwapOfferReply.newBuilder()
- .setBsqSwapOffer(toBsqSwapOfferInfo(offer /* TODO support triggerPrice */).toProtoMessage())
+ .setBsqSwapOffer(toOfferInfo(offer /* TODO support triggerPrice */).toProtoMessage())
.build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
@@ -132,7 +154,7 @@ public void getMyOffer(GetMyOfferRequest req,
try {
OpenOffer openOffer = coreApi.getMyOffer(req.getId());
var reply = GetMyOfferReply.newBuilder()
- .setOffer(toOfferInfo(openOffer).toProtoMessage())
+ .setOffer(OfferInfo.toMyOfferInfo(openOffer).toProtoMessage())
.build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
@@ -142,15 +164,15 @@ public void getMyOffer(GetMyOfferRequest req,
}
@Override
- public void getBsqSwapOffers(GetOffersRequest req,
+ public void getBsqSwapOffers(GetBsqSwapOffersRequest req,
StreamObserver responseObserver) {
try {
- List result = coreApi.getBsqSwapOffers(req.getDirection())
- .stream().map(BsqSwapOfferInfo::toBsqSwapOfferInfo)
+ List result = coreApi.getBsqSwapOffers(req.getDirection())
+ .stream().map(OfferInfo::toOfferInfo)
.collect(Collectors.toList());
var reply = GetBsqSwapOffersReply.newBuilder()
.addAllBsqSwapOffers(result.stream()
- .map(BsqSwapOfferInfo::toProtoMessage)
+ .map(OfferInfo::toProtoMessage)
.collect(Collectors.toList()))
.build();
responseObserver.onNext(reply);
@@ -180,15 +202,15 @@ public void getOffers(GetOffersRequest req,
}
@Override
- public void getMyBsqSwapOffers(GetMyOffersRequest req,
+ public void getMyBsqSwapOffers(GetBsqSwapOffersRequest req,
StreamObserver responseObserver) {
try {
- List result = coreApi.getMyBsqSwapOffers(req.getDirection())
- .stream().map(BsqSwapOfferInfo::toBsqSwapOfferInfo)
+ List result = coreApi.getMyBsqSwapOffers(req.getDirection())
+ .stream().map(OfferInfo::toOfferInfo)
.collect(Collectors.toList());
var reply = GetMyBsqSwapOffersReply.newBuilder()
.addAllBsqSwapOffers(result.stream()
- .map(BsqSwapOfferInfo::toProtoMessage)
+ .map(OfferInfo::toProtoMessage)
.collect(Collectors.toList()))
.build();
responseObserver.onNext(reply);
@@ -204,7 +226,7 @@ public void getMyOffers(GetMyOffersRequest req,
try {
List result = coreApi.getMyOffers(req.getDirection(), req.getCurrencyCode())
.stream()
- .map(OfferInfo::toOfferInfo)
+ .map(OfferInfo::toMyOfferInfo)
.collect(Collectors.toList());
var reply = GetMyOffersReply.newBuilder()
.addAllOffers(result.stream()
@@ -222,17 +244,15 @@ public void getMyOffers(GetMyOffersRequest req,
public void createBsqSwapOffer(CreateBsqSwapOfferRequest req,
StreamObserver responseObserver) {
try {
- //todo PaymentAccount for bsq swap not needed as its just a dummy account
coreApi.createAndPlaceBsqSwapOffer(
req.getDirection(),
req.getAmount(),
req.getMinAmount(),
req.getPrice(),
- /* req.getPaymentAccountId(),*/
offer -> {
- BsqSwapOfferInfo bsqSwapOfferInfo = toBsqSwapOfferInfo(offer);
+ OfferInfo offerInfo = toMyPendingOfferInfo(offer);
CreateBsqSwapOfferReply reply = CreateBsqSwapOfferReply.newBuilder()
- .setBsqSwapOffer(bsqSwapOfferInfo.toProtoMessage())
+ .setBsqSwapOffer(offerInfo.toProtoMessage())
.build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
@@ -261,7 +281,7 @@ public void createOffer(CreateOfferRequest req,
offer -> {
// This result handling consumer's accept operation will return
// the new offer to the gRPC client after async placement is done.
- OfferInfo offerInfo = toPendingOfferInfo(offer);
+ OfferInfo offerInfo = toMyPendingOfferInfo(offer);
CreateOfferReply reply = CreateOfferReply.newBuilder()
.setOffer(offerInfo.toProtoMessage())
.build();
@@ -315,6 +335,7 @@ final Optional rateMeteringInterceptor() {
return getCustomRateMeteringInterceptor(coreApi.getConfig().appDataDir, this.getClass())
.or(() -> Optional.of(CallRateMeteringInterceptor.valueOf(
new HashMap<>() {{
+ put(getGetOfferCategoryMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
put(getGetOfferMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
put(getGetMyOfferMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
put(getGetOffersMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
@@ -325,4 +346,15 @@ final Optional rateMeteringInterceptor() {
}}
)));
}
+
+ private OfferCategory getOfferCategory(String offerId, boolean isMyOffer) {
+ if (coreApi.isAltcoinOffer(offerId, isMyOffer))
+ return ALTCOIN;
+ else if (coreApi.isFiatOffer(offerId, isMyOffer))
+ return FIAT;
+ else if (coreApi.isBsqSwapOffer(offerId, isMyOffer))
+ return BSQ_SWAP;
+ else
+ return UNKNOWN;
+ }
}
diff --git a/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java b/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java
index 5e712e253e1..6a9ce12a7cb 100644
--- a/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java
+++ b/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java
@@ -18,21 +18,19 @@
package bisq.daemon.grpc;
import bisq.core.api.CoreApi;
-import bisq.core.api.model.BsqSwapTradeInfo;
import bisq.core.api.model.TradeInfo;
+import bisq.core.trade.model.TradeModel;
import bisq.core.trade.model.bisq_v1.Trade;
+import bisq.core.trade.model.bsq_swap.BsqSwapTrade;
import bisq.proto.grpc.ConfirmPaymentReceivedReply;
import bisq.proto.grpc.ConfirmPaymentReceivedRequest;
import bisq.proto.grpc.ConfirmPaymentStartedReply;
import bisq.proto.grpc.ConfirmPaymentStartedRequest;
-import bisq.proto.grpc.GetBsqSwapTradeReply;
import bisq.proto.grpc.GetTradeReply;
import bisq.proto.grpc.GetTradeRequest;
import bisq.proto.grpc.KeepFundsReply;
import bisq.proto.grpc.KeepFundsRequest;
-import bisq.proto.grpc.TakeBsqSwapOfferReply;
-import bisq.proto.grpc.TakeBsqSwapOfferRequest;
import bisq.proto.grpc.TakeOfferReply;
import bisq.proto.grpc.TakeOfferRequest;
import bisq.proto.grpc.WithdrawFundsReply;
@@ -48,7 +46,6 @@
import lombok.extern.slf4j.Slf4j;
-import static bisq.core.api.model.BsqSwapTradeInfo.toBsqSwapTradeInfo;
import static bisq.core.api.model.TradeInfo.toNewTradeInfo;
import static bisq.core.api.model.TradeInfo.toTradeInfo;
import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor;
@@ -74,60 +71,49 @@ public GrpcTradesService(CoreApi coreApi, GrpcExceptionHandler exceptionHandler)
}
@Override
- public void getBsqSwapTrade(GetTradeRequest req,
- StreamObserver responseObserver) {
- try {
- var bsqSwapTrade = coreApi.getBsqSwapTrade(req.getTradeId());
- // String role = coreApi.getBsqSwapTradeRole(req.getTradeId());
- var reply = GetBsqSwapTradeReply.newBuilder()
- .setBsqSwapTrade(toBsqSwapTradeInfo(bsqSwapTrade).toProtoMessage())
- .build();
- responseObserver.onNext(reply);
- responseObserver.onCompleted();
- } catch (IllegalArgumentException cause) {
- // Offer makers may call 'gettrade' many times before a trade exists.
- // Log a 'trade not found' warning instead of a full stack trace.
- exceptionHandler.handleExceptionAsWarning(log, "getBsqSwapTrade", cause, responseObserver);
- } catch (Throwable cause) {
- exceptionHandler.handleException(log, cause, responseObserver);
- }
- }
-
- @Override
- public void takeBsqSwapOffer(TakeBsqSwapOfferRequest req,
- StreamObserver responseObserver) {
+ public void takeOffer(TakeOfferRequest req,
+ StreamObserver responseObserver) {
GrpcErrorMessageHandler errorMessageHandler =
new GrpcErrorMessageHandler(getTakeOfferMethod().getFullMethodName(),
responseObserver,
exceptionHandler,
log);
- coreApi.takeBsqSwapOffer(req.getOfferId(),
- req.getPaymentAccountId(),
- req.getTakerFeeCurrencyCode(),
- bsqSwapTrade -> {
- BsqSwapTradeInfo bsqSwapTradeInfo = toBsqSwapTradeInfo(bsqSwapTrade);
- var reply = TakeBsqSwapOfferReply.newBuilder()
- .setBsqSwapTrade(bsqSwapTradeInfo.toProtoMessage())
- .build();
- responseObserver.onNext(reply);
- responseObserver.onCompleted();
- },
- errorMessage -> {
- if (!errorMessageHandler.isErrorHandled())
- errorMessageHandler.handleErrorMessage(errorMessage);
- });
+
+ if (coreApi.isBsqSwapOffer(req.getOfferId(), false)) {
+ coreApi.takeBsqSwapOffer(req.getOfferId(),
+ bsqSwapTrade -> {
+ var reply = buildTakeOfferReply(bsqSwapTrade);
+ responseObserver.onNext(reply);
+ responseObserver.onCompleted();
+ },
+ errorMessage -> {
+ if (!errorMessageHandler.isErrorHandled())
+ errorMessageHandler.handleErrorMessage(errorMessage);
+ });
+ } else {
+ coreApi.takeOffer(req.getOfferId(),
+ req.getPaymentAccountId(),
+ req.getTakerFeeCurrencyCode(),
+ trade -> {
+ var reply = buildTakeOfferReply(trade);
+ responseObserver.onNext(reply);
+ responseObserver.onCompleted();
+ },
+ errorMessage -> {
+ if (!errorMessageHandler.isErrorHandled())
+ errorMessageHandler.handleErrorMessage(errorMessage);
+ });
+ }
}
@Override
public void getTrade(GetTradeRequest req,
StreamObserver responseObserver) {
try {
- Trade trade = coreApi.getTrade(req.getTradeId());
- boolean isMyOffer = coreApi.isMyOffer(trade.getOffer().getId());
- String role = coreApi.getTradeRole(req.getTradeId());
- var reply = GetTradeReply.newBuilder()
- .setTrade(toTradeInfo(trade, role, isMyOffer).toProtoMessage())
- .build();
+ var tradeModel = coreApi.getTradeModel(req.getTradeId());
+ var reply = tradeModel.getOffer().isBsqSwapOffer()
+ ? buildGetTradeReply((BsqSwapTrade) tradeModel)
+ : buildGetTradeReply((Trade) tradeModel);
responseObserver.onNext(reply);
responseObserver.onCompleted();
} catch (IllegalArgumentException cause) {
@@ -139,31 +125,6 @@ public void getTrade(GetTradeRequest req,
}
}
- @Override
- public void takeOffer(TakeOfferRequest req,
- StreamObserver responseObserver) {
- GrpcErrorMessageHandler errorMessageHandler =
- new GrpcErrorMessageHandler(getTakeOfferMethod().getFullMethodName(),
- responseObserver,
- exceptionHandler,
- log);
- coreApi.takeOffer(req.getOfferId(),
- req.getPaymentAccountId(),
- req.getTakerFeeCurrencyCode(),
- trade -> {
- TradeInfo tradeInfo = toNewTradeInfo(trade);
- var reply = TakeOfferReply.newBuilder()
- .setTrade(tradeInfo.toProtoMessage())
- .build();
- responseObserver.onNext(reply);
- responseObserver.onCompleted();
- },
- errorMessage -> {
- if (!errorMessageHandler.isErrorHandled())
- errorMessageHandler.handleErrorMessage(errorMessage);
- });
- }
-
@Override
public void confirmPaymentStarted(ConfirmPaymentStartedRequest req,
StreamObserver responseObserver) {
@@ -228,6 +189,7 @@ final Optional rateMeteringInterceptor() {
new HashMap<>() {{
put(getGetTradeMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS));
put(getTakeOfferMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES));
+ // put(getTakeBsqSwapOfferMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES));
put(getConfirmPaymentStartedMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES));
put(getConfirmPaymentReceivedMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES));
put(getKeepFundsMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES));
@@ -235,4 +197,49 @@ final Optional rateMeteringInterceptor() {
}}
)));
}
+
+ private TakeOfferReply buildTakeOfferReply(TradeModel tradeModel) {
+ TradeInfo tradeInfo;
+ if (tradeModel.getOffer().isBsqSwapOffer()) {
+ BsqSwapTrade bsqSwapTrade = (BsqSwapTrade) tradeModel;
+ String role = getMyRole(bsqSwapTrade);
+ tradeInfo = toNewTradeInfo(bsqSwapTrade, role);
+ } else {
+ tradeInfo = toNewTradeInfo((Trade) tradeModel);
+ }
+ return TakeOfferReply.newBuilder()
+ .setTrade(tradeInfo.toProtoMessage())
+ .build();
+ }
+
+ private GetTradeReply buildGetTradeReply(BsqSwapTrade bsqSwapTrade) {
+ boolean wasMyOffer = wasMyOffer(bsqSwapTrade);
+ String role = getMyRole(bsqSwapTrade);
+ var numConfirmations = coreApi.getTransactionConfirmations(bsqSwapTrade.getTxId());
+ var tradeInfo = toTradeInfo(bsqSwapTrade,
+ role,
+ wasMyOffer,
+ numConfirmations);
+ return GetTradeReply.newBuilder()
+ .setTrade(tradeInfo.toProtoMessage())
+ .build();
+ }
+
+ private GetTradeReply buildGetTradeReply(Trade trade) {
+ boolean wasMyOffer = wasMyOffer(trade);
+ String role = getMyRole(trade);
+ return GetTradeReply.newBuilder()
+ .setTrade(toTradeInfo(trade, role, wasMyOffer).toProtoMessage())
+ .build();
+ }
+
+ private boolean wasMyOffer(TradeModel tradeModel) {
+ return coreApi.isMyOffer(tradeModel.getOffer().getId());
+ }
+
+ private String getMyRole(TradeModel tradeModel) {
+ return tradeModel.getOffer().isBsqSwapOffer()
+ ? coreApi.getBsqSwapTradeRole((BsqSwapTrade) tradeModel)
+ : coreApi.getTradeRole(tradeModel.getId());
+ }
}
diff --git a/proto/src/main/proto/grpc.proto b/proto/src/main/proto/grpc.proto
index ec8235b4042..10a90940db9 100644
--- a/proto/src/main/proto/grpc.proto
+++ b/proto/src/main/proto/grpc.proto
@@ -62,6 +62,8 @@ message GetMethodHelpReply {
///////////////////////////////////////////////////////////////////////////////////////////
service Offers {
+ rpc GetOfferCategory (GetOfferCategoryRequest) returns (GetOfferCategoryReply) {
+ }
rpc GetBsqSwapOffer (GetOfferRequest) returns (GetBsqSwapOfferReply) {
}
rpc GetOffer (GetOfferRequest) returns (GetOfferReply) {
@@ -70,11 +72,11 @@ service Offers {
}
rpc GetMyOffer (GetMyOfferRequest) returns (GetMyOfferReply) {
}
- rpc GetBsqSwapOffers (GetOffersRequest) returns (GetBsqSwapOffersReply) {
+ rpc GetBsqSwapOffers (GetBsqSwapOffersRequest) returns (GetBsqSwapOffersReply) {
}
rpc GetOffers (GetOffersRequest) returns (GetOffersReply) {
}
- rpc GetMyBsqSwapOffers (GetMyOffersRequest) returns (GetMyBsqSwapOffersReply) {
+ rpc GetMyBsqSwapOffers (GetBsqSwapOffersRequest) returns (GetMyBsqSwapOffersReply) {
}
rpc GetMyOffers (GetMyOffersRequest) returns (GetMyOffersReply) {
}
@@ -88,8 +90,23 @@ service Offers {
}
}
+message GetOfferCategoryRequest {
+ string id = 1;
+ bool isMyOffer = 2;
+}
+
+message GetOfferCategoryReply {
+ enum OfferCategory {
+ UNKNOWN = 0;
+ FIAT = 1;
+ ALTCOIN = 2;
+ BSQ_SWAP = 3;
+ }
+ OfferCategory offerCategory = 1;
+}
+
message GetBsqSwapOfferReply {
- BsqSwapOfferInfo bsqSwapOffer = 1;
+ OfferInfo bsqSwapOffer = 1;
}
message GetOfferRequest {
@@ -101,7 +118,7 @@ message GetOfferReply {
}
message GetMyBsqSwapOfferReply {
- BsqSwapOfferInfo bsqSwapOffer = 1;
+ OfferInfo bsqSwapOffer = 1;
}
message GetMyOfferRequest {
@@ -121,8 +138,12 @@ message GetOffersReply {
repeated OfferInfo offers = 1;
}
+message GetBsqSwapOffersRequest {
+ string direction = 1;
+}
+
message GetBsqSwapOffersReply {
- repeated BsqSwapOfferInfo bsqSwapOffers = 1;
+ repeated OfferInfo bsqSwapOffers = 1;
}
message GetMyOffersRequest {
@@ -135,7 +156,7 @@ message GetMyOffersReply {
}
message GetMyBsqSwapOffersReply {
- repeated BsqSwapOfferInfo bsqSwapOffers = 1;
+ repeated OfferInfo bsqSwapOffers = 1;
}
message CreateBsqSwapOfferRequest {
@@ -143,11 +164,10 @@ message CreateBsqSwapOfferRequest {
uint64 amount = 2;
uint64 minAmount = 3;
string price = 4;
- string paymentAccountId = 5;
}
message CreateBsqSwapOfferReply {
- BsqSwapOfferInfo bsqSwapOffer = 1;
+ OfferInfo bsqSwapOffer = 1;
}
message CreateOfferRequest {
@@ -204,25 +224,6 @@ message CancelOfferRequest {
message CancelOfferReply {
}
-message BsqSwapOfferInfo {
- string id = 1;
- string direction = 2;
- uint64 amount = 3;
- uint64 minAmount = 4;
- uint64 price = 5;
- string makerPaymentAccountId = 6;
- string paymentMethodId = 7;
- string paymentMethodShortName = 8;
- string baseCurrencyCode = 9;
- string counterCurrencyCode = 10;
- uint64 getMakerFee = 11;
- uint64 date = 12;
- string ownerNodeAddress = 13;
- string pubKeyRing = 14;
- string versionNr = 15;
- int32 protocolVersion = 16;
-}
-
message OfferInfo {
string id = 1;
string direction = 2;
@@ -250,6 +251,11 @@ message OfferInfo {
bool isActivated = 24;
bool isMyOffer = 25;
bool isMyPendingOffer = 26;
+ bool isBsqSwapOffer = 27;
+ string ownerNodeAddress = 28;
+ string pubKeyRing = 29;
+ string versionNr = 30;
+ int32 protocolVersion = 31;
}
message AvailabilityResultWithDescription {
@@ -377,12 +383,8 @@ message StopReply {
///////////////////////////////////////////////////////////////////////////////////////////
service Trades {
- rpc GetBsqSwapTrade (GetTradeRequest) returns (GetBsqSwapTradeReply) {
- }
rpc GetTrade (GetTradeRequest) returns (GetTradeReply) {
}
- rpc TakeBsqSwapOffer (TakeBsqSwapOfferRequest) returns (TakeBsqSwapOfferReply) {
- }
rpc TakeOffer (TakeOfferRequest) returns (TakeOfferReply) {
}
rpc ConfirmPaymentStarted (ConfirmPaymentStartedRequest) returns (ConfirmPaymentStartedReply) {
@@ -395,17 +397,6 @@ service Trades {
}
}
-message TakeBsqSwapOfferRequest {
- string offerId = 1;
- string paymentAccountId = 2;
- string takerFeeCurrencyCode = 3;
-}
-
-message TakeBsqSwapOfferReply {
- BsqSwapTradeInfo bsqSwapTrade = 1;
- AvailabilityResultWithDescription failureReason = 2;
-}
-
message TakeOfferRequest {
string offerId = 1;
string paymentAccountId = 2;
@@ -431,10 +422,6 @@ message ConfirmPaymentReceivedRequest {
message ConfirmPaymentReceivedReply {
}
-message GetBsqSwapTradeReply {
- BsqSwapTradeInfo bsqSwapTrade = 1;
-}
-
message GetTradeRequest {
string tradeId = 1;
}
@@ -459,37 +446,8 @@ message WithdrawFundsRequest {
message WithdrawFundsReply {
}
-message BsqSwapTradeInfo {
- BsqSwapOfferInfo bsqSwapOfferInfo = 1;
- string tradeId = 2;
- string tempTradingPeerNodeAddress = 3;
- string peerNodeAddress = 4;
- string txId = 5;
- uint64 bsqTradeAmount = 6;
- uint64 bsqMaxTradeAmount = 7;
- uint64 bsqMinTradeAmount = 8;
- uint64 btcTradeAmount = 9;
- uint64 btcMaxTradeAmount = 10;
- uint64 btcMinTradeAmount = 11;
- uint64 tradePrice = 12;
- bool isCurrencyForMakerFeeBtc = 13;
- bool isCurrencyForTakerFeeBtc = 14;
- uint64 bsqMakerTradeFee = 15;
- uint64 btcMakerTradeFee = 16;
- uint64 bsqTakerTradeFee = 17;
- uint64 btcTakerTradeFee = 18;
- uint64 txFeePerVbyte = 19;
- uint64 txFee = 20;
- string makerBsqAddress = 21;
- string makerBtcAddress = 22;
- string takerBsqAddress = 23;
- string takerBtcAddress = 24;
- uint64 takeOfferDate = 25;
- string state = 26;
- string errorMessage = 27;
-}
-
message TradeInfo {
+ // Bisq v1 trade protocol fields.
OfferInfo offer = 1;
string tradeId = 2;
string shortId = 3;
@@ -516,6 +474,8 @@ message TradeInfo {
string contractAsJson = 24;
ContractInfo contract = 25;
uint64 tradeVolume = 26;
+ // Optional Bisq v2+ trade protocol fields.
+ BsqSwapTradeInfo bsqSwapTradeInfo = 28;
}
message ContractInfo {
@@ -533,6 +493,22 @@ message ContractInfo {
uint64 lockTime = 12;
}
+message BsqSwapTradeInfo {
+ // BSQ Swap protocol specific fields not common to Bisq v1 trade protocol fields.
+ string txId = 1;
+ uint64 bsqTradeAmount = 2;
+ uint64 btcTradeAmount = 3;
+ uint64 bsqMakerTradeFee = 4;
+ uint64 bsqTakerTradeFee = 5;
+ uint64 txFeePerVbyte = 6;
+ string makerBsqAddress = 7;
+ string makerBtcAddress = 8;
+ string takerBsqAddress = 9;
+ string takerBtcAddress = 10;
+ uint64 numConfirmations = 11;
+ string errorMessage = 12;
+}
+
message PaymentAccountPayloadInfo {
string id = 1;
string paymentMethodId = 2;