Merge pull request #5093 from ghubstan/02-trading-scripts

Add api trade simulation scripts
This commit is contained in:
Christoph Atteneder 2021-01-21 09:42:14 +01:00 committed by GitHub
commit 570d6a8b38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 1652 additions and 60 deletions

View File

@ -0,0 +1,28 @@
import sys, os, json
# Writes a Bisq json F2F payment account form for the given country_code to the current working directory.
if len(sys.argv) < 2:
print("usage: editf2faccountform.py country_code")
exit(1)
country_code = str(sys.argv[1]).upper()
acct_form = {
"_COMMENTS_": [
"Do not manually edit the paymentMethodId field.",
"Edit the salt field only if you are recreating a payment account on a new installation and wish to preserve the account age."
],
"paymentMethodId": "F2F",
"accountName": "Face to Face Payment Account",
"city": "Anytown",
"contact": "Me",
"country": country_code,
"extraInfo": "",
"salt": ""
}
target=os.path.dirname(os.path.realpath(__file__)) + '/' + 'f2f-acct.json'
with open (target, 'w') as outfile:
json.dump(acct_form, outfile, indent=2)
outfile.write('\n')
exit(0)

View File

@ -0,0 +1,159 @@
#! /bin/bash
# Demonstrates a way to create a limit order (offer) 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 offer.
#
# Prerequisites:
#
# - Linux or OSX with bash, Java 10, or Java 11-12 (JDK language compatibility 10), and bitcoin-core (v0.19, v0.20).
#
# - 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`
#
# - Only regtest btc can be bought or sold with the test payment account.
#
# Usage:
#
# This script must be run from the root of the project, e.g.:
#
# `$ apitest/scripts/limit-order-simulation.sh -l 40000 -d buy -c fr -m 3.00 -a 0.125`
#
# Script options: -l <limit-price> -d <direction> -c <country-code> (-m <mkt-price-margin(%)> || -f <fixed-price>) -a <amount(btc)> [-w <price-poll-interval(s)>]
#
# Example:
#
# Create 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, when the BTC market price rises to or above 40,000 EUR:
#
# `$ apitest/scripts/limit-order-simulation.sh -l 40000 -d sell -c fr -m 0.00 -a 0.125`
APP_HOME=$(pwd -P)
APITEST_SCRIPTS_HOME="${APP_HOME}/apitest/scripts"
source "${APITEST_SCRIPTS_HOME}/trade-simulation-env.sh"
source "${APITEST_SCRIPTS_HOME}/trade-simulation-utils.sh"
checksetup
parselimitorderopts "$@"
printdate "Started ${APP_BASE_NAME} with parameters:"
printscriptparams
printbreak
editpaymentaccountform "$COUNTRY_CODE"
exitoncommandalert $?
cat "${APITEST_SCRIPTS_HOME}/${F2F_ACCT_FORM}"
printbreak
# Create F2F payment accounts for $COUNTRY_CODE, and get the $CURRENCY_CODE.
printdate "Creating Alice's face to face ${COUNTRY_CODE} payment account."
CMD="${CLI_BASE} --port=${ALICE_PORT} createpaymentacct --payment-account-form=${APITEST_SCRIPTS_HOME}/${F2F_ACCT_FORM}"
printdate "ALICE CLI: ${CMD}"
CMD_OUTPUT=$(createpaymentacct "${CMD}")
exitoncommandalert $?
echo "${CMD_OUTPUT}"
ALICE_ACCT_ID=$(getnewpaymentacctid "${CMD_OUTPUT}")
exitoncommandalert $?
CURRENCY_CODE=$(getnewpaymentacctcurrency "${CMD_OUTPUT}")
exitoncommandalert $?
printdate "ALICE F2F payment-account-id = ${ALICE_ACCT_ID}, currency-code = ${CURRENCY_CODE}."
printbreak
printdate "Creating Bob's face to face ${COUNTRY_CODE} payment account."
CMD="${CLI_BASE} --port=${BOB_PORT} createpaymentacct --payment-account-form=${APITEST_SCRIPTS_HOME}/${F2F_ACCT_FORM}"
printdate "BOB CLI: ${CMD}"
CMD_OUTPUT=$(createpaymentacct "${CMD}")
exitoncommandalert $?
echo "${CMD_OUTPUT}"
BOB_ACCT_ID=$(getnewpaymentacctid "${CMD_OUTPUT}")
exitoncommandalert $?
CURRENCY_CODE=$(getnewpaymentacctcurrency "${CMD_OUTPUT}")
exitoncommandalert $?
printdate "BOB F2F payment-account-id = ${BOB_ACCT_ID}, currency-code = ${CURRENCY_CODE}."
printbreak
# Bob & Alice now have matching payment accounts, now loop until the price limit is reached, then create an offer.
if [ "$DIRECTION" = "BUY" ]
then
printdate "Create a BUY / ${CURRENCY_CODE} offer when the market price falls to or below ${LIMIT_PRICE} ${CURRENCY_CODE}."
else
printdate "Create a SELL / ${CURRENCY_CODE} offer when the market price rises to or above ${LIMIT_PRICE} ${CURRENCY_CODE}."
fi
DONE=0
while : ; do
if [ "$DONE" -ne 0 ]; then
break
fi
CURRENT_PRICE=$(getcurrentprice "$ALICE_PORT" "$CURRENCY_CODE")
exitoncommandalert $?
printdate "Current Market Price: $CURRENT_PRICE"
if [ "$DIRECTION" = "BUY" ] && [ "$CURRENT_PRICE" -le "$LIMIT_PRICE" ]; then
printdate "Limit price reached."
DONE=1
break
fi
if [ "$DIRECTION" = "SELL" ] && [ "$CURRENT_PRICE" -ge "$LIMIT_PRICE" ]; then
printdate "Limit price reached."
DONE=1
break
fi
sleep "$WAIT"
done
printdate "ALICE: Creating ${DIRECTION} ${CURRENCY_CODE} offer with payment acct ${ALICE_ACCT_ID}."
CMD="$CLI_BASE --port=${ALICE_PORT} createoffer"
CMD+=" --payment-account=${ALICE_ACCT_ID}"
CMD+=" --direction=${DIRECTION}"
CMD+=" --currency-code=${CURRENCY_CODE}"
CMD+=" --amount=${AMOUNT}"
if [ -z "${MKT_PRICE_MARGIN}" ]; then
CMD+=" --fixed-price=${FIXED_PRICE}"
else
CMD+=" --market-price-margin=${MKT_PRICE_MARGIN}"
fi
CMD+=" --security-deposit=50.0"
CMD+=" --fee-currency=BSQ"
printdate "ALICE CLI: ${CMD}"
OFFER_ID=$(createoffer "${CMD}")
exitoncommandalert $?
printdate "ALICE: Created offer with id: ${OFFER_ID}."
printbreak
sleeptraced 3
# Show Alice's new 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 7
# Generate some btc blocks.
printdate "Generating btc blocks after publishing Alice's offer."
genbtcblocks 3 3
printbreak
sleeptraced 5
# Show Alice's offer in Bob's CLI.
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}"
exit 0

View File

@ -0,0 +1,219 @@
#! /bin/bash
# This file must be sourced by the main driver.
export CLI_BASE="./bisq-cli --password=xyz"
export ARBITRATOR_PORT=9997
export ALICE_PORT=9998
export BOB_PORT=9999
export F2F_ACCT_FORM="f2f-acct.json"
checksetup() {
apitestusage() {
echo "The apitest harness must be running a local bitcoin regtest node, a seednode, arbitration node, and Bob & Alice daemons."
echo ""
echo "From the project's root dir, start all supporting nodes from a terminal:"
echo "./bisq-apitest --apiPassword=xyz --supportingApps=bitcoind,seednode,arbdaemon,alicedaemon,bobdaemon --shutdownAfterTests=false"
echo ""
echo "Register dispute agents in the arbitration daemon after it initializes."
echo "./bisq-cli --password=xyz --port=9997 registerdisputeagent --dispute-agent-type=mediator \
--registration-key=6ac43ea1df2a290c1c8391736aa42e4339c5cb4f110ff0257a13b63211977b7a"
echo "./bisq-cli --password=xyz --port=9997 registerdisputeagent --dispute-agent-type=refundagent \
--registration-key=6ac43ea1df2a290c1c8391736aa42e4339c5cb4f110ff0257a13b63211977b7a"
exit 1;
}
printdate "Checking ${APP_HOME} for some expected directories and files."
if [ -d "${APP_HOME}/apitest" ]; then
printdate "Subproject apitest exists.";
else
printdate "Error: Subproject apitest not found, maybe because you are not running the script from the project root dir."
exit 1
fi
if [ -f "${APP_HOME}/bisq-cli" ]; then
printdate "The bisq-cli script exists.";
else
printdate "Error: The bisq-cli script not found, maybe because you are not running the script from the project root dir."
exit 1
fi
printdate "Checking to see local bitcoind is running."
checkbitcoindrunning
printdate "Checking to see bisq servers are running."
if pgrep -f "bisq.seednode.SeedNodeMain" > /dev/null ; then
printdate "The seednode is running on host."
else
printdate "Error: seed is not running on host, exiting."
apitestusage
fi
if pgrep -f "bisq.daemon.app.BisqDaemonMain --appName=bisq-BTC_REGTEST_Arb_dao" > /dev/null ; then
printdate "The arbitration node is running on host."
else
printdate "Error: arbitration node is not running on host, exiting."
apitestusage
fi
if pgrep -f "bisq.daemon.app.BisqDaemonMain --appName=bisq-BTC_REGTEST_Alice_dao" > /dev/null ; then
printdate "Alice's daemon node is running on host."
else
printdate "Error: Alice's daemon node is not running on host, exiting."
apitestusage
fi
if pgrep -f "bisq.daemon.app.BisqDaemonMain --appName=bisq-BTC_REGTEST_Bob_dao" > /dev/null ; then
printdate "Bob's daemon node is running on host."
else
printdate "Error: Bob's daemon node is not running on host, exiting."
apitestusage
fi
}
parseopts() {
usage() {
echo "Usage: $0 [-d buy|sell] [-c <country-code>] [-f <fixed-price> || -m <margin-from-price>] [-a <amount in btc>]" 1>&2
exit 1;
}
local OPTIND o d c f m a
while getopts "d:c:f:m:a:" o; do
case "${o}" in
d) d=$(echo "${OPTARG}" | tr '[:lower:]' '[:upper:]')
((d == "BUY" || d == "SELL")) || usage
export DIRECTION=${d}
;;
c) c=$(echo "${OPTARG}"| tr '[:lower:]' '[:upper:]')
export COUNTRY_CODE=${c}
;;
f) f=${OPTARG}
export FIXED_PRICE=${f}
;;
m) m=${OPTARG}
export MKT_PRICE_MARGIN=${m}
;;
a) a=${OPTARG}
export AMOUNT=${a}
;;
*) usage ;;
esac
done
shift $((OPTIND-1))
if [ -z "${d}" ] || [ -z "${c}" ] || [ -z "${a}" ]; then
usage
fi
if [ -z "${f}" ] && [ -z "${m}" ]; then
usage
fi
if [ -n "${f}" ] && [ -n "${m}" ]; then
printdate "Must use margin-from-price param (-m) or fixed-price param (-f), not both."
usage
fi
if [ "$DIRECTION" = "SELL" ]
then
export BOB_ROLE="(taker/buyer)"
export ALICE_ROLE="(maker/seller)"
else
export BOB_ROLE="(taker/seller)"
export ALICE_ROLE="(maker/buyer)"
fi
}
parselimitorderopts() {
usage() {
echo "Usage: $0 [-l limit-price] [-d buy|sell] [-c <country-code>] [-f <fixed-price> || -m <margin-from-price>] [-a <amount in btc>] [-w <price-poll-interval(s)>]" 1>&2
exit 1;
}
local OPTIND o l d c f m a w
while getopts "l:d:c:f:m:a:w:" o; do
case "${o}" in
l) l=${OPTARG}
export LIMIT_PRICE=${l}
;;
d) d=$(echo "${OPTARG}" | tr '[:lower:]' '[:upper:]')
((d == "BUY" || d == "SELL")) || usage
export DIRECTION=${d}
;;
c) c=$(echo "${OPTARG}"| tr '[:lower:]' '[:upper:]')
export COUNTRY_CODE=${c}
;;
f) f=${OPTARG}
export FIXED_PRICE=${f}
;;
m) m=${OPTARG}
export MKT_PRICE_MARGIN=${m}
;;
a) a=${OPTARG}
export AMOUNT=${a}
;;
w) w=${OPTARG}
export WAIT=${w}
;;
*) usage ;;
esac
done
shift $((OPTIND-1))
if [ -z "${l}" ]; then
usage
fi
if [ -z "${d}" ] || [ -z "${c}" ] || [ -z "${a}" ]; then
usage
fi
if [ -z "${f}" ] && [ -z "${m}" ]; then
usage
fi
if [ -n "${f}" ] && [ -n "${m}" ]; then
printdate "Must use margin-from-price param (-m) or fixed-price param (-f), not both."
usage
fi
if [ -z "${w}" ]; then
WAIT=120
elif [ "$w" -lt 20 ]; then
printdate "The -w <price-poll-interval(s)> option is too low, minimum allowed is 20s. Using default 120s."
WAIT=120
fi
}
checkbitcoindrunning() {
# There may be a '+' char in the path and we have to escape it for pgrep.
if [[ ${APP_HOME} == *"+"* ]]; then
ESCAPED_APP_HOME=$(escapepluschar "${APP_HOME}")
else
ESCAPED_APP_HOME="${APP_HOME}"
fi
if pgrep -f "bitcoind -datadir=${ESCAPED_APP_HOME}/apitest/build/resources/main/Bitcoin-regtest" > /dev/null ; then
printdate "The regtest bitcoind node is running on host."
else
printdate "Error: regtest bitcoind node is not running on host, exiting."
apitestusage
fi
}
printscriptparams() {
if [ -n "${LIMIT_PRICE+1}" ]; then
echo " LIMIT_PRICE = ${LIMIT_PRICE}"
fi
echo " DIRECTION = ${DIRECTION}"
echo " COUNTRY_CODE = ${COUNTRY_CODE}"
echo " FIXED_PRICE = ${FIXED_PRICE}"
echo " MKT_PRICE_MARGIN = ${MKT_PRICE_MARGIN}"
echo " AMOUNT = ${AMOUNT}"
if [ -n "${BOB_ROLE+1}" ]; then
echo " BOB_ROLE = ${BOB_ROLE}"
fi
if [ -n "${ALICE_ROLE+1}" ]; then
echo " ALICE_ROLE = ${ALICE_ROLE}"
fi
if [ -n "${WAIT+1}" ]; then
echo " WAIT = ${WAIT}"
fi
}

View File

@ -0,0 +1,179 @@
#! /bin/bash
# This file must be sourced by the main driver.
source "${APITEST_SCRIPTS_HOME}/trade-simulation-env.sh"
printdate() {
echo "[$(date)] $@"
}
printbreak() {
echo ""
echo ""
}
printcmd() {
echo -en "$@\n"
}
sleeptraced() {
PERIOD="$1"
printdate "sleeping for $PERIOD"
sleep "$PERIOD"
}
commandalert() {
# Used in a script function when it needs to fail early with an error message, & pass the error code to the caller.
# usage: commandalert <$?> <msg-prefix>
if [ "$1" -ne 0 ]
then
printdate "Error: $2" >&2
exit "$1"
fi
}
# TODO rename exitonalert ?
exitoncommandalert() {
# Used in a parent script when you need it to fail immediately, with no error message.
# usage: exitoncommandalert <$?>
if [ "$1" -ne 0 ]
then
exit "$1"
fi
}
registerdisputeagents() {
# Silently register dev dispute agents. It's easy to forget.
REG_KEY="6ac43ea1df2a290c1c8391736aa42e4339c5cb4f110ff0257a13b63211977b7a"
CMD="${CLI_BASE} --port=${ARBITRATOR_PORT} registerdisputeagent --dispute-agent-type=mediator --registration-key=${REG_KEY}"
SILENT=$($CMD)
commandalert $? "Could not register dev/test mediator."
CMD="${CLI_BASE} --port=${ARBITRATOR_PORT} registerdisputeagent --dispute-agent-type=refundagent --registration-key=${REG_KEY}"
SILENT=$($CMD)
commandalert $? "Could not register dev/test refundagent."
# Do something with $SILENT to keep codacy happy.
echo "$SILENT" > /dev/null
}
getbtcoreaddress() {
CMD="bitcoin-cli -regtest -rpcport=19443 -rpcuser=apitest -rpcpassword=apitest getnewaddress"
NEW_ADDRESS=$($CMD)
echo "${NEW_ADDRESS}"
}
genbtcblocks() {
NUM_BLOCKS="$1"
SECONDS_BETWEEN_BLOCKS="$2"
ADDR_PARAM="$(getbtcoreaddress)"
CMD_PREFIX="bitcoin-cli -regtest -rpcport=19443 -rpcuser=apitest -rpcpassword=apitest generatetoaddress 1"
# Print the generatetoaddress command with double quoted address param, to make it cut & pastable from the console.
printdate "$CMD_PREFIX \"$ADDR_PARAM\""
# Now create the full generatetoaddress command to be run now.
CMD="$CMD_PREFIX $ADDR_PARAM"
for i in $(seq -f "%02g" 1 "$NUM_BLOCKS")
do
NEW_BLOCK_HASH=$(genbtcblock "$CMD")
printdate "Block Hash #$i:${NEW_BLOCK_HASH}"
sleep "$SECONDS_BETWEEN_BLOCKS"
done
}
genbtcblock() {
CMD="$1"
NEW_BLOCK_HASH=$($CMD | sed -n '2p')
echo "$NEW_BLOCK_HASH"
}
escapepluschar() {
STRING="$1"
NEW_STRING=$(echo "${STRING//+/\\+}")
echo "${NEW_STRING}"
}
printbalances() {
PORT="$1"
printcmd "${CLI_BASE} --port=${PORT} getbalance"
$CLI_BASE --port="$PORT" getbalance
}
getpaymentaccountmethods() {
CMD="$1"
CMD_OUTPUT=$($CMD)
commandalert $? "Could not get payment method ids."
printdate "Payment Method IDs:"
echo "${CMD_OUTPUT}"
}
getpaymentaccountform() {
CMD="$1"
CMD_OUTPUT=$($CMD)
commandalert $? "Could not get new payment account form."
echo "${CMD_OUTPUT}"
}
editpaymentaccountform() {
COUNTRY_CODE="$1"
CMD="python3 ${APITEST_SCRIPTS_HOME}/editf2faccountform.py $COUNTRY_CODE"
CMD_OUTPUT=$($CMD)
commandalert $? "Could not edit payment account form."
printdate "Saved payment account form as ${F2F_ACCT_FORM}."
}
getnewpaymentacctid() {
CREATE_PAYMENT_ACCT_OUTPUT="$1"
PAYMENT_ACCT_DETAIL=$(echo -e "${CREATE_PAYMENT_ACCT_OUTPUT}" | sed -n '3p')
ACCT_ID=$(echo -e "$PAYMENT_ACCT_DETAIL" | awk '{print $NF}')
echo "${ACCT_ID}"
}
getnewpaymentacctcurrency() {
CREATE_PAYMENT_ACCT_OUTPUT="$1"
PAYMENT_ACCT_DETAIL=$(echo -e "${CREATE_PAYMENT_ACCT_OUTPUT}" | sed -n '3p')
# This is brittle; it requires the account name field to have N words,
# e.g, "Face to Face Payment Account" as defined in editf2faccountform.py.
CURRENCY_CODE=$(echo -e "$PAYMENT_ACCT_DETAIL" | awk '{print $6}')
echo "${CURRENCY_CODE}"
}
createpaymentacct() {
CMD="$1"
CMD_OUTPUT=$($CMD)
commandalert $? "Could not create new payment account."
echo "${CMD_OUTPUT}"
}
getpaymentaccounts() {
PORT="$1"
printcmd "${CLI_BASE} --port=${PORT} getpaymentaccts"
CMD="$CLI_BASE --port=$PORT getpaymentaccts"
CMD_OUTPUT=$($CMD)
commandalert $? "Could not get payment accounts."
echo "${CMD_OUTPUT}"
}
createoffer() {
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}"
}
getcurrentprice() {
PORT="$1"
CURRENCY_CODE="$2"
CMD="$CLI_BASE --port=$PORT getbtcprice --currency-code=$CURRENCY_CODE"
CMD_OUTPUT=$($CMD)
commandalert $? "Could not get current market $CURRENCY_CODE price."
FLOOR=$(echo "$CMD_OUTPUT" | cut -d'.' -f 1)
commandalert $? "Could not get the floor of the current market $CURRENCY_CODE price."
INTEGER=$(echo "$FLOOR" | tr -cd '[[:digit:]]')
commandalert $? "Could not convert the current market $CURRENCY_CODE price string to an integer."
echo "$INTEGER"
}

View File

@ -0,0 +1,240 @@
#! /bin/bash
# Runs fiat <-> btc trading scenarios 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).
#
# - 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`
#
# - Only regtest btc can be bought or sold with the test payment account.
#
# Usage:
#
# This script must be run from the root of the project, e.g.:
#
# `$ apitest/scripts/trade-simulation.sh -d buy -c fr -m 3.00 -a 0.125`
#
# Script options: -d <direction> -c <country-code> -m <mkt-price-margin(%)> - f <fixed-price> -a <amount(btc)>
#
# 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:
#
# `$ 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
# payment account:
#
# `$ apitest/scripts/trade-simulation.sh -d sell -c fr -f 38000 -a 0.125`
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"
checksetup
parseopts "$@"
printdate "Started ${APP_BASE_NAME} with parameters:"
printscriptparams
printbreak
registerdisputeagents
printdate "Alice looks for the ID of the face to face payment account method (Bob will use same payment method)."
CMD="${CLI_BASE} --port=${ALICE_PORT} getpaymentmethods"
printdate "ALICE CLI: ${CMD}"
getpaymentaccountmethods "$CMD"
printbreak
printdate "Alice uses the F2F payment method id to create a face to face payment account in country ${COUNTRY_CODE}."
CMD="${CLI_BASE} --port=${ALICE_PORT} getpaymentacctform --payment-method-id=F2F"
printdate "ALICE CLI: ${CMD}"
getpaymentaccountform "$CMD"
printbreak
printdate "Bob & Alice edit their ${COUNTRY_CODE} payment account forms, and renames them to ${F2F_ACCT_FORM}"
editpaymentaccountform "$COUNTRY_CODE"
cat "${APITEST_SCRIPTS_HOME}/${F2F_ACCT_FORM}"
# Remove the autogenerated json template because we are going to use one created by a python script in the next step.
CMD="rm -v ${APP_HOME}/f2f_*.json"
DELETE_JSON_TEMPLATE=$($CMD)
printdate "$DELETE_JSON_TEMPLATE"
printbreak
printdate "Bob and Alice create their face to face ${COUNTRY_CODE} payment accounts."
CMD="${CLI_BASE} --port=${BOB_PORT} createpaymentacct --payment-account-form=${APITEST_SCRIPTS_HOME}/${F2F_ACCT_FORM}"
printdate "BOB CLI: ${CMD}"
CMD_OUTPUT=$(createpaymentacct "${CMD}")
echo "${CMD_OUTPUT}"
BOB_ACCT_ID=$(getnewpaymentacctid "${CMD_OUTPUT}")
BOB_ACCT_CURRENCY_CODE=$(getnewpaymentacctcurrency "${CMD_OUTPUT}")
printdate "BOB F2F payment-account-id = ${BOB_ACCT_ID}, currency-code = ${BOB_ACCT_CURRENCY_CODE}."
printbreak
CMD="${CLI_BASE} --port=${ALICE_PORT} createpaymentacct --payment-account-form=${APITEST_SCRIPTS_HOME}/${F2F_ACCT_FORM}"
printdate "ALICE CLI: ${CMD}"
CMD_OUTPUT=$(createpaymentacct "${CMD}")
echo "${CMD_OUTPUT}"
ALICE_ACCT_ID=$(getnewpaymentacctid "${CMD_OUTPUT}")
ALICE_ACCT_CURRENCY_CODE=$(getnewpaymentacctcurrency "${CMD_OUTPUT}")
printdate "ALICE F2F payment-account-id = ${ALICE_ACCT_ID}, currency-code = ${ALICE_ACCT_CURRENCY_CODE}."
printbreak
printdate "ALICE ${ALICE_ROLE}: Creating ${DIRECTION} ${ALICE_ACCT_CURRENCY_CODE} offer with payment acct ${ALICE_ACCT_ID}."
CURRENT_PRICE=$(getcurrentprice "$ALICE_PORT" "$ALICE_ACCT_CURRENCY_CODE")
exitoncommandalert $?
printdate "Current Market Price: $CURRENT_PRICE"
CMD="$CLI_BASE --port=${ALICE_PORT} createoffer"
CMD+=" --payment-account=${ALICE_ACCT_ID}"
CMD+=" --direction=${DIRECTION}"
CMD+=" --currency-code=${ALICE_ACCT_CURRENCY_CODE}"
CMD+=" --amount=${AMOUNT}"
if [ -z "${MKT_PRICE_MARGIN}" ]; then
CMD+=" --fixed-price=${FIXED_PRICE}"
else
CMD+=" --market-price-margin=${MKT_PRICE_MARGIN}"
fi
CMD+=" --security-deposit=15.0"
CMD+=" --fee-currency=BSQ"
printdate "ALICE CLI: ${CMD}"
OFFER_ID=$(createoffer "${CMD}")
exitoncommandalert $?
printdate "ALICE ${ALICE_ROLE}: Created offer with id: ${OFFER_ID}."
printbreak
sleeptraced 3
# Show Alice's new offer.
printdate "ALICE ${ALICE_ROLE}: 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 7
# Generate some btc blocks.
printdate "Generating btc blocks after publishing Alice's offer."
genbtcblocks 3 5
printbreak
sleeptraced 10
# List offers.
printdate "BOB ${BOB_ROLE}: Looking at ${DIRECTION} ${BOB_ACCT_CURRENCY_CODE} offers."
CMD="$CLI_BASE --port=${BOB_PORT} getoffers --direction=${DIRECTION} --currency-code=${BOB_ACCT_CURRENCY_CODE}"
printdate "BOB CLI: ${CMD}"
OFFERS=$($CMD)
exitoncommandalert $?
echo "${OFFERS}"
printbreak
sleeptraced 3
# Take offer.
printdate "BOB ${BOB_ROLE}: Taking offer ${OFFER_ID} with payment acct ${BOB_ACCT_ID}."
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."
echo "${TRADE}"
printbreak
sleeptraced 10
# Generating some btc blocks
printdate "Generating btc blocks after Bob takes Alice's offer."
genbtcblocks 3 3
printbreak
sleeptraced 6
# Send payment sent and received messages.
if [ "${DIRECTION}" = "BUY" ]
then
PAYER="ALICE ${ALICE_ROLE}"
PAYER_PORT=${ALICE_PORT}
PAYER_CLI="ALICE CLI"
PAYEE="BOB ${BOB_ROLE}"
PAYEE_PORT=${BOB_PORT}
PAYEE_CLI="BOB CLI"
else
PAYER="BOB ${BOB_ROLE}"
PAYER_PORT=${BOB_PORT}
PAYER_CLI="BOB CLI"
PAYEE="ALICE ${ALICE_ROLE}"
PAYEE_PORT=${ALICE_PORT}
PAYEE_CLI="ALICE CLI"
fi
# Confirm payment started.
printdate "${PAYER}: Sending fiat payment sent msg."
CMD="$CLI_BASE --port=${PAYER_PORT} confirmpaymentstarted --trade-id=${OFFER_ID}"
printdate "${PAYER_CLI}: ${CMD}"
SENT_MSG=$($CMD)
commandalert $? "Could not send confirmpaymentstarted message."
printdate "${SENT_MSG}"
printbreak
sleeptraced 2
printdate "Generating btc blocks after fiat payment sent msg."
genbtcblocks 3 5
sleeptraced 2
# Confirm payment received.
printdate "${PAYEE}: Sending fiat payment received msg."
CMD="$CLI_BASE --port=${PAYEE_PORT} confirmpaymentreceived --trade-id=${OFFER_ID}"
printdate "${PAYEE_CLI}: ${CMD}"
RCVD_MSG=$($CMD)
commandalert $? "Could not send confirmpaymentreceived message."
printdate "${RCVD_MSG}"
printbreak
sleeptraced 4
# Generate some btc blocks
printdate "Generating btc blocks after fiat transfer."
genbtcblocks 3 5
printbreak
sleeptraced 3
# Complete the trade on the seller side.
if [ "${DIRECTION}" = "BUY" ]
then
printdate "BOB ${BOB_ROLE}: Closing trade by keeping funds in Bisq wallet."
CMD="$CLI_BASE --port=${BOB_PORT} keepfunds --trade-id=${OFFER_ID}"
printdate "BOB CLI: ${CMD}"
else
printdate "ALICE (taker): Closing trade by keeping funds in Bisq wallet."
CMD="$CLI_BASE --port=${ALICE_PORT} keepfunds --trade-id=${OFFER_ID}"
printdate "ALICE CLI: ${CMD}"
fi
KEEP_FUNDS_MSG=$($CMD)
commandalert $? "Could close trade with keepfunds command."
printdate "${KEEP_FUNDS_MSG}"
sleeptraced 5
printbreak
# Get balances after trade completion.
printdate "Bob & Alice's balances after trade:"
printdate "ALICE CLI:"
printbalances "$ALICE_PORT"
printbreak
printdate "BOB CLI:"
printbalances "$BOB_PORT"
printbreak
exit 0

View File

@ -40,6 +40,7 @@ import bisq.proto.grpc.GetUnusedBsqAddressRequest;
import bisq.proto.grpc.GetVersionRequest;
import bisq.proto.grpc.KeepFundsRequest;
import bisq.proto.grpc.LockWalletRequest;
import bisq.proto.grpc.MarketPriceRequest;
import bisq.proto.grpc.OfferInfo;
import bisq.proto.grpc.RegisterDisputeAgentRequest;
import bisq.proto.grpc.RemoveWalletPasswordRequest;
@ -75,6 +76,7 @@ import java.util.List;
import lombok.extern.slf4j.Slf4j;
import static bisq.cli.CurrencyFormat.formatMarketPrice;
import static bisq.cli.CurrencyFormat.formatTxFeeRateInfo;
import static bisq.cli.CurrencyFormat.toSatoshis;
import static bisq.cli.CurrencyFormat.toSecurityDepositAsPct;
@ -98,6 +100,7 @@ import bisq.cli.opts.CancelOfferOptionParser;
import bisq.cli.opts.CreateOfferOptionParser;
import bisq.cli.opts.CreatePaymentAcctOptionParser;
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;
@ -189,6 +192,7 @@ public class CliMain {
var helpService = grpcStubs.helpService;
var offersService = grpcStubs.offersService;
var paymentAccountsService = grpcStubs.paymentAccountsService;
var priceService = grpcStubs.priceService;
var tradesService = grpcStubs.tradesService;
var versionService = grpcStubs.versionService;
var walletsService = grpcStubs.walletsService;
@ -243,6 +247,20 @@ public class CliMain {
out.println(formatAddressBalanceTbl(singletonList(reply.getAddressBalanceInfo())));
return;
}
case getbtcprice: {
var opts = new GetBTCMarketPriceOptionParser(args).parse();
if (opts.isForHelp()) {
out.println(getMethodHelp(helpService, method));
return;
}
var currencyCode = opts.getCurrencyCode();
var request = MarketPriceRequest.newBuilder()
.setCurrencyCode(currencyCode)
.build();
var reply = priceService.getMarketPrice(request);
out.println(formatMarketPrice(reply.getPrice()));
return;
}
case getfundingaddresses: {
if (new SimpleMethodOptionParser(args).parse().isForHelp()) {
out.println(getMethodHelp(helpService, method));
@ -802,15 +820,18 @@ public class CliMain {
stream.println();
stream.format(rowFormat, getaddressbalance.name(), "--address=<btc-address>", "Get server wallet address balance");
stream.println();
stream.format(rowFormat, getbtcprice.name(), "--currency-code=<currency-code>", "Get current market btc price");
stream.println();
stream.format(rowFormat, getfundingaddresses.name(), "", "Get BTC funding addresses");
stream.println();
stream.format(rowFormat, getunusedbsqaddress.name(), "", "Get unused BSQ address");
stream.println();
stream.format(rowFormat, sendbsq.name(), "--address=<btc-address> --amount=<btc-amount> \\", "Send BSQ");
stream.format(rowFormat, sendbsq.name(), "--address=<bsq-address> --amount=<bsq-amount> \\", "Send BSQ");
stream.format(rowFormat, "", "[--tx-fee-rate=<sats/byte>]", "");
stream.println();
stream.format(rowFormat, sendbtc.name(), "--address=<bsq-address> --amount=<bsq-amount> \\", "Send BTC");
stream.format(rowFormat, sendbtc.name(), "--address=<btc-address> --amount=<btc-amount> \\", "Send BTC");
stream.format(rowFormat, "", "[--tx-fee-rate=<sats/byte>]", "");
stream.format(rowFormat, "", "[--memo=<\"memo\">]", "");
stream.println();
stream.format(rowFormat, gettxfeerate.name(), "", "Get current tx fee rate in sats/byte");
stream.println();

View File

@ -77,6 +77,11 @@ public class CurrencyFormat {
: formatOfferVolume(volume);
}
static String formatMarketPrice(double price) {
NUMBER_FORMAT.setMinimumFractionDigits(4);
return NUMBER_FORMAT.format(price);
}
static String formatOfferPrice(long price) {
NUMBER_FORMAT.setMaximumFractionDigits(4);
NUMBER_FORMAT.setMinimumFractionDigits(4);

View File

@ -21,36 +21,37 @@ package bisq.cli;
* Currently supported api methods.
*/
public enum Method {
createoffer,
canceloffer,
getoffer,
getmyoffer,
getoffers,
getmyoffers,
takeoffer,
gettrade,
confirmpaymentstarted,
confirmpaymentreceived,
keepfunds,
withdrawfunds,
getpaymentmethods,
getpaymentacctform,
confirmpaymentstarted,
createoffer,
createpaymentacct,
getpaymentaccts,
getversion,
getbalance,
getaddressbalance,
getbalance,
getbtcprice,
getfundingaddresses,
getmyoffer,
getmyoffers,
getoffer,
getoffers,
getpaymentacctform,
getpaymentaccts,
getpaymentmethods,
gettrade,
gettransaction,
gettxfeerate,
getunusedbsqaddress,
getversion,
keepfunds,
lockwallet,
registerdisputeagent,
removewalletpassword,
sendbsq,
sendbtc,
gettxfeerate,
settxfeerate,
unsettxfeerate,
gettransaction,
lockwallet,
unlockwallet,
removewalletpassword,
setwalletpassword,
registerdisputeagent
takeoffer,
unlockwallet,
unsettxfeerate,
withdrawfunds
}

View File

@ -0,0 +1,52 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.cli.opts;
import joptsimple.OptionSpec;
import static bisq.cli.opts.OptLabel.OPT_CURRENCY_CODE;
import static joptsimple.internal.Strings.EMPTY;
public class GetBTCMarketPriceOptionParser extends AbstractMethodOptionParser implements MethodOpts {
final OptionSpec<String> currencyCodeOpt = parser.accepts(OPT_CURRENCY_CODE, "currency-code")
.withRequiredArg()
.defaultsTo(EMPTY);
public GetBTCMarketPriceOptionParser(String[] args) {
super(args);
}
public GetBTCMarketPriceOptionParser parse() {
super.parse();
// Short circuit opt validation if user just wants help.
if (options.has(helpOpt))
return this;
if (!options.has(currencyCodeOpt))
throw new IllegalArgumentException("no currency code specified");
return this;
}
public String getCurrencyCode() {
return options.valueOf(currencyCodeOpt);
}
}

View File

@ -27,7 +27,7 @@ import static joptsimple.internal.Strings.EMPTY;
public class WithdrawFundsOptionParser extends AbstractMethodOptionParser implements MethodOpts {
final OptionSpec<String> tradeIdOpt = parser.accepts(OPT_TRADE_ID, "id of trade to get")
final OptionSpec<String> tradeIdOpt = parser.accepts(OPT_TRADE_ID, "id of trade")
.withRequiredArg()
.defaultsTo(EMPTY);

View File

@ -73,7 +73,8 @@ public class CoreApi {
@Inject
public CoreApi(Config config,
CoreDisputeAgentsService coreDisputeAgentsService,
CoreHelpService coreHelpService, CoreOffersService coreOffersService,
CoreHelpService coreHelpService,
CoreOffersService coreOffersService,
CorePaymentAccountsService paymentAccountsService,
CorePriceService corePriceService,
CoreTradesService coreTradesService,
@ -212,8 +213,8 @@ public class CoreApi {
// Prices
///////////////////////////////////////////////////////////////////////////////////////////
public double getMarketPrice(String currencyCode) {
return corePriceService.getMarketPrice(currencyCode);
public void getMarketPrice(String currencyCode, Consumer<Double> resultHandler) {
corePriceService.getMarketPrice(currencyCode, resultHandler);
}
///////////////////////////////////////////////////////////////////////////////////////////

View File

@ -17,17 +17,18 @@
package bisq.core.api;
import bisq.core.provider.price.MarketPrice;
import bisq.core.provider.price.PriceFeedService;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.function.Consumer;
import lombok.extern.slf4j.Slf4j;
import static bisq.common.util.MathUtils.roundDouble;
import static bisq.core.locale.CurrencyUtil.isFiatCurrency;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
@Singleton
@Slf4j
@ -40,15 +41,29 @@ class CorePriceService {
this.priceFeedService = priceFeedService;
}
public double getMarketPrice(String currencyCode) {
public void getMarketPrice(String currencyCode, Consumer<Double> resultHandler) {
String upperCaseCurrencyCode = currencyCode.toUpperCase();
if (!isFiatCurrency(upperCaseCurrencyCode))
throw new IllegalStateException(format("%s is not a valid currency code", upperCaseCurrencyCode));
if (!priceFeedService.hasPrices())
throw new IllegalStateException("price feed service has no prices");
MarketPrice marketPrice = priceFeedService.getMarketPrice(currencyCode.toUpperCase());
if (requireNonNull(marketPrice).isPriceAvailable()) {
return roundDouble(marketPrice.getPrice(), 4);
} else {
throw new IllegalStateException(format("'%s' price is not available", currencyCode));
try {
priceFeedService.setCurrencyCode(upperCaseCurrencyCode);
} catch (Throwable throwable) {
log.warn("Could not set currency code in PriceFeedService", throwable);
}
priceFeedService.requestPriceFeed(price -> {
if (price > 0) {
log.info("{} price feed request returned {}", upperCaseCurrencyCode, price);
resultHandler.accept(roundDouble(price, 4));
} else {
throw new IllegalStateException(format("%s price is not available", upperCaseCurrencyCode));
}
},
(errorMessage, throwable) -> log.warn(errorMessage, throwable));
}
}

View File

@ -129,26 +129,6 @@ public class CreateOfferService {
minAmount.value,
buyerSecurityDepositAsDouble);
// Log an approximate api CLI 'createoffer' dev/test param list.
log.info("cli's createoffer positional option names: paymentAccountId direction currencyCode amount minAmount"
+ " useMarketBasedPrice fixedPrice|marketPriceMargin buyerSecurityDeposit");
log.info("cli's createoffer positional option values: {} " +
"{} " +
"{} " +
"{} " +
"{} " +
"{} " +
"{} " +
"{}",
paymentAccount.getId(),
direction.name(),
currencyCode,
amount.value,
minAmount.value,
useMarketBasedPrice,
(useMarketBasedPrice ? marketPriceMargin : price.getValue()),
buyerSecurityDepositAsDouble);
long creationTime = new Date().getTime();
NodeAddress makerAddress = p2PService.getAddress();
boolean useMarketBasedPriceValue = useMarketBasedPrice &&

View File

@ -0,0 +1,26 @@
canceloffer
NAME
----
canceloffer - cancel an existing offer to buy or sell BTC
SYNOPSIS
--------
canceloffer
--offer-id=<offer-id>
DESCRIPTION
-----------
Cancel an existing offer. The offer will be removed from other Bisq users' offer views,
and paid transaction fees will be forfeited.
OPTIONS
-------
--offer-id
The ID of the buy or sell offer to cancel.
EXAMPLES
--------
To cancel an offer with ID 83e8b2e2-51b6-4f39-a748-3ebd29c22aea:
$ ./bisq-cli --password=xyz --port=9998 canceloffer -offer-id=83e8b2e2-51b6-4f39-a748-3ebd29c22aea

View File

@ -0,0 +1,27 @@
confirmpaymentreceived
NAME
----
confirmpaymentreceived - confirm payment has been received
SYNOPSIS
--------
confirmpaymentreceived
--trade-id=<trade-id>
DESCRIPTION
-----------
After the seller receives payment from the BTC buyer, confirmpaymentreceived notifies
the buyer the payment has arrived. The seller can release locked BTC only after the
this confirmation message has been sent.
OPTIONS
-------
--trade-id
The ID of the trade (the full offer-id).
EXAMPLES
--------
A BTC seller has taken an offer with ID 83e8b2e2-51b6-4f39-a748-3ebd29c22aea, and has recently
received the required fiat payment from the buyer's fiat account:
$ ./bisq-cli --password=xyz --port=9998 confirmpaymentreceived -trade-id=83e8b2e2-51b6-4f39-a748-3ebd29c22aea

View File

@ -0,0 +1,26 @@
confirmpaymentstarted
NAME
----
confirmpaymentstarted - confirm payment has been sent
SYNOPSIS
--------
confirmpaymentstarted
--trade-id=<trade-id>
DESCRIPTION
-----------
After the buyer initiates payment to the BTC seller, confirmpaymentstarted notifies
the seller to begin watching for a funds deposit in her payment account.
OPTIONS
-------
--trade-id
The ID of the trade (the full offer-id).
EXAMPLES
--------
A BTC buyer has taken an offer with ID 83e8b2e2-51b6-4f39-a748-3ebd29c22aea, and has recently
initiated the required fiat payment to the seller's fiat account:
$ ./bisq-cli --password=xyz --port=9998 confirmpaymentstarted -trade-id=83e8b2e2-51b6-4f39-a748-3ebd29c22aea

View File

@ -0,0 +1,46 @@
createpaymentacct
NAME
----
createpaymentacct - create a payment account
SYNOPSIS
--------
createpaymentacct
--payment-account-form=<path>
DESCRIPTION
-----------
Create a Bisq trading account with a payment account form.
The details of the payment account are defined in a manually edited json file generated
by a getpaymentacctform command, e.g.,
{
"_COMMENTS_": [
"Do not manually edit the paymentMethodId field.",
"Edit the salt field only if you are recreating a payment account on a new installation and wish to preserve the account age."
],
"paymentMethodId": "SEPA",
"accountName": "your accountname",
"bic": "your bic",
"country": "your country",
"holderName": "your holdername",
"iban": "your iban",
"salt": ""
}
EXAMPLES
--------
To create a new SEPA payment account, find the payment-method-id for the getpaymentacctform command:
$ ./bisq-cli --password=xyz --port=9998 getpaymentmethods
Get a new, blank SEPA payment account form:
$ ./bisq-cli --password=xyz --port=9998 getpaymentacctform --payment-method-id=SEPA
The previous command created a json file named sepa_1610817857085.json. The timestamp
in the file name is to ensure each generated file is uniquely named (you can rename the file).
Manually edit the json file, and pass the file's path to the createpaymentacct command:
$ ./bisq-cli --password=xyz --port=9998 createpaymentacct --payment-account-form=sepa_1610817857085.json

View File

@ -0,0 +1,23 @@
getaddressbalance
NAME
----
getaddressbalance - get btc address balance
SYNOPSIS
--------
getaddressbalance
--address=<btc-address>
DESCRIPTION
-----------
Returns the balance of a BTC address in the Bisq server's wallet.
OPTIONS
-------
--address=<btc-address>
The BTC address.
EXAMPLES
--------
$ ./bisq-cli --password=xyz --port=9998 getaddressbalance --address=bcrt1qygvsqmyt8jyhtp7l3zwqm7s7v3nar6vkc2luz3

View File

@ -0,0 +1,30 @@
getbalance
NAME
----
getbalance - get wallet balance(s)
SYNOPSIS
--------
getbalance
[--currency-code=<bsq|btc>]
DESCRIPTION
-----------
Returns full balance information for Bisq BSQ and/or BTC wallets.
OPTIONS
-------
--currency-code=<bsq|btc>
The three letter Bisq wallet crypto currency code.
EXAMPLES
--------
Show full BSQ and BTC wallet balance information:
$ ./bisq-cli --password=xyz --port=9998 getbalance
Show full BSQ wallet balance information:
$ ./bisq-cli --password=xyz --port=9998 getbalance --currency-code=bsq
Show full BTC wallet balance information:
$ ./bisq-cli --password=xyz --port=9998 getbalance --currency-code=btc

View File

@ -0,0 +1,30 @@
getbtcprice
NAME
----
getbtcprice - get current btc market price
SYNOPSIS
--------
getbtcprice
--currency-code=<eur|usd>
DESCRIPTION
-----------
Returns the current market BTC price for the given currency-code.
OPTIONS
-------
--currency-code
The three letter code for the fiat currency code, e.g., EUR, USD, BRL, ...
EXAMPLES
--------
Get the current BTC market price in Euros:
$ ./bisq-cli --password=xyz --port=9998 getbtcprice --currency-code=eur
Get the current BTC market price in Brazilian Reais:
$ ./bisq-cli --password=xyz --port=9998 getbtcprice --currency-code=brl

View File

@ -0,0 +1,25 @@
getmyoffer
NAME
----
getmyoffer - get your offer to buy or sell BTC
SYNOPSIS
--------
getmyoffer
--offer-id=<offer-id>
DESCRIPTION
-----------
List one of your existing offers' details.
OPTIONS
-------
--offer-id
The ID of your buy or sell offer.
EXAMPLES
--------
To view your offer with ID 83e8b2e2-51b6-4f39-a748-3ebd29c22aea:
$ ./bisq-cli --password=xyz --port=9998 getmyoffer -offer-id=83e8b2e2-51b6-4f39-a748-3ebd29c22aea

View File

@ -0,0 +1,33 @@
getmyoffers
NAME
----
getmyoffers - get your own buy or sell BTC offers for a fiat currency
SYNOPSIS
--------
getmyoffers
--direction=<buy|sell>
--currency-code=<eur|usd>
DESCRIPTION
-----------
List your existing offers for a direction (SELL|BUY) and currency (EUR|GBP|USD|BRL|...).
OPTIONS
-------
--direction
The direction of the offer (BUY or SELL).
--currency-code
The three letter code for the fiat used to buy or sell BTC, e.g., EUR, USD, BRL, ...
EXAMPLES
--------
List all of your existing BUY offers for BRL:
$ ./bisq-cli --password=xyz --port=9998 getmyoffers --direction=buy --currency-code=brl
List all of your existing SELL offers for EUR:
$ ./bisq-cli --password=xyz --port=9998 getmyoffers --direction=sell --currency-code=eur

View File

@ -0,0 +1,26 @@
getoffer
NAME
----
getoffer - get an offer to buy or sell BTC
SYNOPSIS
--------
getoffer
--offer-id=<offer-id>
DESCRIPTION
-----------
List an existing offer's details. The offer must not be one of your own.
The offer must be available to take with one of your matching payment accounts.
OPTIONS
-------
--offer-id
The ID of the buy or sell offer to view.
EXAMPLES
--------
To view an offer with ID 83e8b2e2-51b6-4f39-a748-3ebd29c22aea:
$ ./bisq-cli --password=xyz --port=9998 getoffer -offer-id=83e8b2e2-51b6-4f39-a748-3ebd29c22aea

View File

@ -0,0 +1,39 @@
getoffers
NAME
----
getoffers - get available buy or sell BTC offers for a fiat currency
SYNOPSIS
--------
getoffers
--direction=<buy|sell>
--currency-code=<eur|usd>
DESCRIPTION
-----------
List existing offers for a direction (SELL|BUY) and currency (EUR|GBP|USD|BRL|...).
All of the listed offers will be available for the taking because you have a
matching payment account, and none of the offers listed will be one of yours.
OPTIONS
-------
--direction
The direction of the offer (BUY or SELL).
--currency-code
The three letter code for the fiat used to buy or sell BTC, e.g., EUR, USD, BRL, ...
EXAMPLES
--------
You have one Brazilian Real payment account with a face-to-face payment method type.
To view available offers to BUY BTC with BRL, created by other users with the same
face-to-fact account type:
$ ./bisq-cli --password=xyz --port=9998 getoffers --direction=buy --currency-code=brl
You have several EUR payment accounts, each with a different payment method type.
To view available offers to SELL BTC with EUR, created by other users having at
least one payment account that matches any of your own:
$ ./bisq-cli --password=xyz --port=9998 getoffers --direction=sell --currency-code=eur

View File

@ -0,0 +1,44 @@
getpaymentacctform
NAME
----
getpaymentacctform - get a blank payment account form for a payment method
SYNOPSIS
--------
getpaymentacctform
--payment-method-id=<payment-method-id>
DESCRIPTION
-----------
Returns a new, blank payment account form as a json file, e.g.,
{
"_COMMENTS_": [
"Do not manually edit the paymentMethodId field.",
"Edit the salt field only if you are recreating a payment account on a new installation and wish to preserve the account age."
],
"paymentMethodId": "CLEAR_X_CHANGE",
"accountName": "your accountname",
"emailOrMobileNr": "your emailormobilenr",
"holderName": "your holdername",
"salt": ""
}
This form is manually edited, and used as a parameter to the createpaymentacct command,
which creates the new payment account.
EXAMPLES
--------
To create a new CLEAR_X_CHANGE (Zelle) payment account, find the payment-method-id for
the getpaymentacctform command:
$ ./bisq-cli --password=xyz --port=9998 getpaymentmethods
Get a new, blank CLEAR_X_CHANGE (Zelle) payment account form:
$ ./bisq-cli --password=xyz --port=9998 getpaymentacctform --payment-method-id=CLEAR_X_CHANGE_ID
The previous command created a json file named clear_x_change_1610818248040.json. The timestamp
in the file name is to ensure each generated file is uniquely named (you can rename the file).
Manually edit the json file, and pass the file's path to the createpaymentacct command:
$ ./bisq-cli --password=xyz --port=9998 createpaymentacct --payment-account-form=clear_x_change_1610818248040.json

View File

@ -0,0 +1,32 @@
gettrade
NAME
----
gettrade - get a buy or sell BTC trade
SYNOPSIS
--------
gettrade
--trade-id=<trade-id>
[--show-contract=<true|false>]
DESCRIPTION
-----------
List details of a trade with the given trade-id. If the trade has not yet been completed,
the details can inform each side of the trade of the current phase of the trade protocol.
OPTIONS
-------
--trade-id
The ID of the trade (the full offer-id).
--show-contract
Optionally display the trade's full contract details in json format. The default = false.
EXAMPLES
--------
To see the summary of a trade with ID 83e8b2e2-51b6-4f39-a748-3ebd29c22aea:
$ ./bisq-cli --password=xyz --port=9998 gettrade -trade-id=83e8b2e2-51b6-4f39-a748-3ebd29c22aea
To see the full contract for a trade with ID 83e8b2e2-51b6-4f39-a748-3ebd29c22aea:
$ ./bisq-cli --password=xyz --port=9998 gettrade -trade-id=83e8b2e2-51b6-4f39-a748-3ebd29c22aea --show-contract=true

View File

@ -0,0 +1,27 @@
gettransaction
NAME
----
gettransaction - get transaction summary
SYNOPSIS
--------
gettransaction
--transaction-id=<transaction-id>
DESCRIPTION
-----------
Returns a very brief summary of a BTC transaction created by the Bisq server.
To see full transaction details, use a bitcoin-core client or an online block explorer.
OPTIONS
-------
--transaction-id
The ID of the BTC transaction.
EXAMPLES
--------
To see the summary of a transaction with ID 282dc2a5755219a49ee9f6d46a31a2cbaec6624beba96548180eccb1f004cdd8:
$ ./bisq-cli --password=xyz --port=9998 gettransaction \
-transaction-id=282dc2a5755219a49ee9f6d46a31a2cbaec6624beba96548180eccb1f004cdd8

View File

@ -0,0 +1,31 @@
keepfunds
NAME
----
keepfunds - keep BTC received during a trade in Bisq wallet
SYNOPSIS
--------
keepfunds
--trade-id=<trade-id>
DESCRIPTION
-----------
A BTC buyer completes the final step in the trade protocol by keeping received BTC in his
Bisq wallet. This step may not seem necessary from the buyer's perspective, but it is
necessary for correct transition of a trade's state to CLOSED, within the Bisq server.
The alternative way to close out the trade is to send the received BTC to an external
BTC wallet, using the withdrawfunds command.
OPTIONS
-------
--trade-id
The ID of the trade (the full offer-id).
EXAMPLES
--------
A BTC seller has informed the buyer that fiat payment has been received for trade with ID
83e8b2e2-51b6-4f39-a748-3ebd29c22aea, and locked BTC has been released to the buyer.
The BTC buyer closes out the trade by keeping the received BTC in her Bisq wallet:
$ ./bisq-cli --password=xyz --port=9998 keepfunds -trade-id=83e8b2e2-51b6-4f39-a748-3ebd29c22aea

View File

@ -14,4 +14,5 @@ Locks an unlocked wallet before an unlockwallet timeout expires.
EXAMPLES
--------
Immediately lock an encrypted wallet set to automatically lock in the future:
$ ./bisq-cli --password=xyz --port=9998 lockwallet

View File

@ -0,0 +1,19 @@
removewalletpassword
NAME
----
removewalletpassword - remove a Bisq wallet's encryption password
SYNOPSIS
--------
removewalletpassword
--wallet-password=<wallet-password>
--timeout=<seconds>
DESCRIPTION
-----------
Remove an encryption password from an encrypted Bisq wallet.
EXAMPLES
--------
$ ./bisq-cli --password=xyz --port=9998 removewalletpassword --wallet-password=mypassword

View File

@ -0,0 +1,38 @@
sendbsq
NAME
----
sendbsq - send BSQ to an external wallet
SYNOPSIS
--------
sendbsq
--address=<btc-address>
--amount=<btc-amount>
[--tx-fee-rate=<sats/byte>]
DESCRIPTION
-----------
Send BSQ from your Bisq wallet to an external BSQ address.
OPTIONS
-------
--address
The destination BSQ address for the send transaction.
--amount
The amount of BSQ to send.
--tx-fee-rate
An optional transaction fee rate (sats/byte) for the transaction. The user is
responsible for choosing a fee rate that will be accepted by the network in a
reasonable amount of time, and the fee rate must be greater than 1 (sats/byte).
EXAMPLES
--------
Send 500 BSQ to address Bn3PCQgRwhkrGnaMp1RYwt9tFwL51YELqne with a default transaction fee rate:
$ ./bisq-cli --password=xyz --port=9998 sendbsq --address=Bn3PCQgRwhkrGnaMp1RYwt9tFwL51YELqne --amount=500.00
Send 3000 BSQ to address Bn3PCQgRwhkrGnaMp1RYwt9tFwL51YELqne with transaction fee rate of 40 sats/byte:
$ ./bisq-cli --password=xyz --port=9998 sendbsq --address=Bn3PCQgRwhkrGnaMp1RYwt9tFwL51YELqne --amount=3000.00 \
--tx-fee-rate=40

View File

@ -0,0 +1,51 @@
sendbtc
NAME
----
sendbtc - send BTC to an external wallet
SYNOPSIS
--------
sendbtc
--address=<btc-address>
--amount=<btc-amount>
[--tx-fee-rate=<sats/byte>]
[--memo=<"memo">]
DESCRIPTION
-----------
Send BTC from your Bisq wallet to an external BTC address.
OPTIONS
-------
--address
The destination BTC address for the send transaction.
--amount
The amount of BTC to send.
--tx-fee-rate
An optional transaction fee rate (sats/byte) for the transaction. The user is
responsible for choosing a fee rate that will be accepted by the network in a
reasonable amount of time, and the fee rate must be greater than 1 (sats/byte).
--memo
An optional memo to be saved with the send btc transaction.
A multi word memo must be enclosed in double quotes.
EXAMPLES
--------
Send 0.10 BTC to address bcrt1qygvsqmyt8jyhtp7l3zwqm7s7v3nar6vkc2luz3 with a default
transaction fee rate:
$ ./bisq-cli --password=xyz --port=9998 sendbtc --address=bcrt1qygvsqmyt8jyhtp7l3zwqm7s7v3nar6vkc2luz3 --amount=0.10
Send 0.05 BTC to address bcrt1qygvsqmyt8jyhtp7l3zwqm7s7v3nar6vkc2luz3 with a transaction
fee rate of 10 sats/byte:
$ ./bisq-cli --password=xyz --port=9998 sendbtc --address=bcrt1qygvsqmyt8jyhtp7l3zwqm7s7v3nar6vkc2luz3 --amount=0.05 \
--tx-fee-rate=10
Send 0.005 BTC to address bcrt1qygvsqmyt8jyhtp7l3zwqm7s7v3nar6vkc2luz3 with a transaction
fee rate of 40 sats/byte, and save a memo with the send transaction:
$ ./bisq-cli --password=xyz --port=9998 sendbtc --address=bcrt1qygvsqmyt8jyhtp7l3zwqm7s7v3nar6vkc2luz3 --amount=0.005 \
--tx-fee-rate=40
--memo="note to self"

View File

@ -0,0 +1,19 @@
settxfeerate
NAME
----
settxfeerate - set custom transaction fee rate preference
SYNOPSIS
--------
settxfeerate
--tx-fee-rate=<sats/byte>
DESCRIPTION
-----------
Sets the user's custom transaction fee rate preference.
EXAMPLES
--------
Set custom transaction fee rate to 25 sats/byte:
$ ./bisq-cli --password=xyz --port=9998 settxfeerate --tx-fee-rate=25

View File

@ -0,0 +1,25 @@
setwalletpassword
NAME
----
setwalletpassword - set Bisq wallet password
SYNOPSIS
--------
setwalletpassword
--wallet-password=<wallet-password>
--new-wallet-password=<new-wallet-password>
DESCRIPTION
-----------
Encrypts a Bisq wallet with a password. If the optional new wallet password option is
present, a new wallet password replaces the existing password
EXAMPLES
--------
Encrypt an unencrypted Bisq wallet with a password:
$ ./bisq-cli --password=xyz --port=9998 setwalletpassword --wallet-password=mypassword
Set a new password on a Bisq wallet that is already encrypted:
$ ./bisq-cli --password=xyz --port=9998 setwalletpassword --wallet-password=myoldpassword \
--new-wallet-password=mynewpassword

View File

@ -0,0 +1,21 @@
unlockwallet
NAME
----
unlockwallet - unlock an encrypted Bisq wallet
SYNOPSIS
--------
unlockwallet
--wallet-password=<wallet-password>
--timeout=<seconds>
DESCRIPTION
-----------
Unlocks an encrypted Bisq wallet for a specified number of seconds.
The timeout can be manually overridden with the lockwallet command.
EXAMPLES
--------
Unlock a wallet encrypted with the wallet-password "mypassword" for 30 seconds:
$ ./bisq-cli --password=xyz --port=9998 unlockwallet --wallet-password=mypassword --timeout=30

View File

@ -14,4 +14,5 @@ Unsets (removes) the transaction fee rate user preference.
EXAMPLES
--------
Remove the user's custom transaction fee rate preference:
$ ./bisq-cli --password=xyz --port=9998 unsettxfeerate

View File

@ -0,0 +1,50 @@
withdrawfunds
NAME
----
withdrawfunds - send BTC received during a trade to an external BTC wallet
SYNOPSIS
--------
withdrawfunds
--trade-id=<trade-id>
--address=<btc-address>
[--memo=<"memo">]
DESCRIPTION
-----------
A BTC buyer completes the final step in the trade protocol by sending received BTC to
an external BTC wallet.
The alternative way to close out the trade is to keep the received BTC in the Bisq wallet,
using the keepfunds command.
The buyer needs to complete the trade protocol using the keepfunds or withdrawfunds or command.
This step may not seem necessary from the buyer's perspective, but it is necessary for correct
transition of a trade's state to CLOSED, within the Bisq server.
OPTIONS
-------
--trade-id
The ID of the trade (the full offer-id).
--address
The destination btc address for the send btc transaction.
--memo
An optional memo to be saved with the send btc transaction.
A multi word memo must be enclosed in double quotes.
EXAMPLES
--------
A BTC seller has informed the buyer that fiat payment has been received for trade with ID
83e8b2e2-51b6-4f39-a748-3ebd29c22aea, and locked BTC has been released to the buyer.
The BTC buyer closes out the trade by sending the received BTC to an external BTC wallet:
$ ./bisq-cli --password=xyz --port=9998 withdrawfunds -trade-id=83e8b2e2-51b6-4f39-a748-3ebd29c22aea \
--address=2N5J6MyjAsWnashimGiNwoRzUXThsQzRmbv (bitcoin regtest address)
A seller sends a trade's BTC proceeds to an external wallet, and includes an optional memo:
$ ./bisq-cli --password=xyz --port=9998 withdrawfunds -trade-id=83e8b2e2-51b6-4f39-a748-3ebd29c22aea \
--address=2N5J6MyjAsWnashimGiNwoRzUXThsQzRmbv
--memo="note to self"

View File

@ -45,10 +45,12 @@ class GrpcPriceService extends PriceGrpc.PriceImplBase {
public void getMarketPrice(MarketPriceRequest req,
StreamObserver<MarketPriceReply> responseObserver) {
try {
double price = coreApi.getMarketPrice(req.getCurrencyCode());
coreApi.getMarketPrice(req.getCurrencyCode(),
price -> {
var reply = MarketPriceReply.newBuilder().setPrice(price).build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
});
} catch (Throwable cause) {
exceptionHandler.handleException(cause, responseObserver);
}