mirror of
https://github.com/JoinMarket-Org/joinmarket-clientserver.git
synced 2026-08-13 12:33:40 +02:00
132 lines
5.2 KiB
Python
Executable file
132 lines
5.2 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
import sys
|
|
from datetime import datetime
|
|
from decimal import Decimal
|
|
from json import loads
|
|
from optparse import OptionParser
|
|
|
|
from jmbase import EXIT_ARGERROR, jmprint, get_log, utxostr_to_utxo, EXIT_FAILURE
|
|
from jmbitcoin import amount_to_sat, amount_to_str
|
|
from jmclient import add_base_options, load_program_config, jm_single, get_bond_values
|
|
|
|
DESCRIPTION = """Given either a Bitcoin UTXO in the form TXID:n
|
|
(e.g., 0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098:0)
|
|
or an amount in either satoshi or bitcoin (e.g., 150000, 0.1, 10.123, 10btc),
|
|
calculate fidelity bond values for all possible locktimes in a one-year period
|
|
(12 months, you can change that with the `-m --months` option).
|
|
By default it uses the values from your joinmarket.cfg,
|
|
you can override these with the `-i --interest` and `-e --exponent` options.
|
|
Additionally, you can export the orderbook from ob-watcher.py and use the data here
|
|
with the `-o --orderbook` option, this will compare the results from this script
|
|
with the fidelity bonds in the orderbook.
|
|
"""
|
|
|
|
log = get_log()
|
|
|
|
|
|
def main() -> None:
|
|
parser = OptionParser(
|
|
usage="usage: %prog [options] UTXO or amount",
|
|
description=DESCRIPTION,
|
|
)
|
|
add_base_options(parser)
|
|
parser.add_option(
|
|
"-i",
|
|
"--interest",
|
|
action="store",
|
|
type="float",
|
|
dest="interest",
|
|
help="Interest rate to use for fidelity bond calculation (instead of interest_rate config)",
|
|
)
|
|
parser.add_option(
|
|
"-e",
|
|
"--exponent",
|
|
action="store",
|
|
type="float",
|
|
dest="exponent",
|
|
help="Exponent to use for fidelity bond calculation (instead of bond_value_exponent config)",
|
|
)
|
|
parser.add_option(
|
|
"-m",
|
|
"--months",
|
|
action="store",
|
|
type="int",
|
|
dest="months",
|
|
help="For how many months to calculate the fidelity bond values, each month has its own stats (default 12)",
|
|
default=12,
|
|
)
|
|
parser.add_option(
|
|
"-o",
|
|
"--orderbook",
|
|
action="store",
|
|
type="str",
|
|
dest="path_to_json",
|
|
help="Path to the exported orderbook in JSON format",
|
|
)
|
|
|
|
options, args = parser.parse_args()
|
|
load_program_config(config_path=options.datadir)
|
|
if len(args) != 1:
|
|
log.error("Invalid arguments, see --help")
|
|
sys.exit(EXIT_ARGERROR)
|
|
if options.path_to_json:
|
|
try:
|
|
with open(options.path_to_json, "r", encoding="UTF-8") as orderbook:
|
|
orderbook = loads(orderbook.read())
|
|
except FileNotFoundError as exc:
|
|
log.error(exc)
|
|
sys.exit(EXIT_ARGERROR)
|
|
else:
|
|
orderbook = None
|
|
try:
|
|
amount = amount_to_sat(args[0])
|
|
confirm_time = None
|
|
except ValueError:
|
|
# If it's not a valid amount then it has to be a UTXO
|
|
if jm_single().bc_interface is None:
|
|
log.error("For calculation based on UTXO access to Bitcoin Core is required")
|
|
sys.exit(EXIT_FAILURE)
|
|
success, utxo = utxostr_to_utxo(args[0])
|
|
if not success:
|
|
# utxo contains the error message
|
|
log.error(utxo)
|
|
sys.exit(EXIT_ARGERROR)
|
|
utxo_data = jm_single().bc_interface.query_utxo_set(utxo, includeconfs=True)[0]
|
|
amount = utxo_data["value"]
|
|
if utxo_data["confirms"] == 0:
|
|
log.warning("Given UTXO is unconfirmed, current time will be used as confirmation time")
|
|
confirm_time = None
|
|
elif utxo_data["confirms"] < 0:
|
|
log.error("Given UTXO is invalid, reason: conflicted")
|
|
sys.exit(EXIT_ARGERROR)
|
|
else:
|
|
current_height = jm_single().bc_interface.get_current_block_height()
|
|
block_hash = jm_single().bc_interface.get_block_hash(current_height - utxo_data["confirms"] + 1)
|
|
confirm_time = jm_single().bc_interface.get_block_time(block_hash)
|
|
|
|
parameters, results = get_bond_values(amount,
|
|
options.months,
|
|
confirm_time,
|
|
options.interest,
|
|
options.exponent,
|
|
orderbook)
|
|
jmprint(f"Amount locked: {amount_to_str(amount)}")
|
|
jmprint(f"Confirmation time: {datetime.fromtimestamp(parameters['confirm_time'])}")
|
|
jmprint(f"Interest rate: {parameters['interest']} ({parameters['interest'] * 100}%)")
|
|
jmprint(f"Exponent: {parameters['exponent']}")
|
|
jmprint(f"\nFIDELITY BOND VALUES (BTC^{parameters['exponent']})")
|
|
jmprint("\nSee /docs/fidelity-bonds.md for complete formula and more")
|
|
|
|
for result in results:
|
|
locktime = datetime.fromtimestamp(result["locktime"])
|
|
# Mimic the locktime value the user would have to insert to create such fidelity bond
|
|
jmprint(f"\nLocktime: {locktime.year}-{locktime.month}")
|
|
# Mimic orderbook value
|
|
jmprint(f"Bond value: {float(Decimal(result['value']) / Decimal(1e16)):.16f}")
|
|
if options.path_to_json:
|
|
jmprint(f"Weight: {result['weight']:.5f} ({result['weight'] * 100:.2f}% of all bonds)")
|
|
jmprint(f"Top {result['percentile']}% of the orderbook by value")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|