mirror of
https://github.com/JoinMarket-Org/joinmarket-clientserver.git
synced 2026-08-13 12:33:40 +02:00
Allow both BTC and sat amounts for single send / CJ
This commit is contained in:
parent
9db732553d
commit
b2e4308a90
6 changed files with 70 additions and 33 deletions
|
|
@ -7,4 +7,5 @@ from jmbitcoin.secp256k1_transaction import *
|
|||
from jmbitcoin.secp256k1_deterministic import *
|
||||
from jmbitcoin.btscript import *
|
||||
from jmbitcoin.bech32 import *
|
||||
from jmbitcoin.amount import *
|
||||
|
||||
|
|
|
|||
46
jmbitcoin/jmbitcoin/amount.py
Normal file
46
jmbitcoin/jmbitcoin/amount.py
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
from decimal import Decimal
|
||||
|
||||
def btc_to_sat(btc):
|
||||
return int(Decimal(btc) * Decimal('1e8'))
|
||||
|
||||
def sat_to_btc(sat):
|
||||
return Decimal(sat) / Decimal('1e8')
|
||||
|
||||
# 1 = 0.00000001 BTC = 1sat
|
||||
# 1sat = 0.00000001 BTC = 1sat
|
||||
# 1.123sat = 0.00000001 BTC = 1sat
|
||||
# 0.00000001 = 0.00000001 BTC = 1sat
|
||||
# 0.00000001btc = 0.00000001 BTC = 1sat
|
||||
# 1.00000000 = 1.00000000 BTC = 100000000sat
|
||||
# 1.12300000sat = 0.00000001 BTC = 1sat
|
||||
# 1btc = 1.00000000 BTC = 10000000sat
|
||||
|
||||
def amount_to_sat(amount_str):
|
||||
amount_str = str(amount_str)
|
||||
if amount_str.lower().endswith("btc"):
|
||||
return int(btc_to_sat(amount_str[:-3]))
|
||||
elif amount_str.lower().endswith("sat"):
|
||||
return int(Decimal(amount_str[:-3]))
|
||||
elif "." in amount_str:
|
||||
return int(btc_to_sat(amount_str))
|
||||
else:
|
||||
return int(Decimal(amount_str))
|
||||
|
||||
def amount_to_btc(amount_str):
|
||||
return amount_to_sat(amount_str) / Decimal('1e8')
|
||||
|
||||
def amount_to_sat_str(amount_str):
|
||||
return str(amount_to_sat(amount_str)) + " sat"
|
||||
|
||||
def amount_to_btc_str(amount_str):
|
||||
return str(amount_to_btc(amount_str)) + " BTC"
|
||||
|
||||
def amount_to_str(amount_str):
|
||||
return amount_to_btc_str(amount_str) + " (" + amount_to_sat_str(amount_str) + ")"
|
||||
|
||||
def sat_to_str(sat):
|
||||
return '%.8f' % sat_to_btc(sat)
|
||||
|
||||
def sat_to_str_p(sat):
|
||||
return '%+.8f' % sat_to_btc(sat)
|
||||
|
||||
|
|
@ -12,7 +12,7 @@ from .configure import jm_single, validate_address
|
|||
from .schedule import human_readable_schedule_entry, tweak_tumble_schedule,\
|
||||
schedule_to_text
|
||||
from .wallet import BaseWallet, estimate_tx_fee
|
||||
from jmbitcoin import deserialize, mktx, serialize, txhash
|
||||
from jmbitcoin import deserialize, mktx, serialize, txhash, amount_to_str
|
||||
log = get_log()
|
||||
|
||||
"""
|
||||
|
|
@ -74,9 +74,9 @@ def direct_send(wallet_service, amount, mixdepth, destaddr, answeryes=False,
|
|||
outs.append({"value": changeval, "address": change_addr})
|
||||
|
||||
#Now ready to construct transaction
|
||||
log.info("Using a fee of : " + str(fee_est) + " satoshis.")
|
||||
log.info("Using a fee of : " + amount_to_str(fee_est) + ".")
|
||||
if amount != 0:
|
||||
log.info("Using a change value of: " + str(changeval) + " satoshis.")
|
||||
log.info("Using a change value of: " + amount_to_str(changeval) + ".")
|
||||
txsigned = sign_tx(wallet_service, mktx(list(utxos.keys()), outs), utxos)
|
||||
log.info("Got signed transaction:\n")
|
||||
log.info(pformat(txsigned))
|
||||
|
|
@ -84,7 +84,7 @@ def direct_send(wallet_service, amount, mixdepth, destaddr, answeryes=False,
|
|||
log.info("In serialized form (for copy-paste):")
|
||||
log.info(tx)
|
||||
actual_amount = amount if amount != 0 else total_inputs_val - fee_est
|
||||
log.info("Sends: " + str(actual_amount) + " satoshis to address: " + destaddr)
|
||||
log.info("Sends: " + amount_to_str(actual_amount) + " to address: " + destaddr)
|
||||
if not answeryes:
|
||||
if not accept_callback:
|
||||
if input('Would you like to push to the network? (y/n):')[0] != 'y':
|
||||
|
|
|
|||
|
|
@ -636,24 +636,20 @@ def wallet_fetch_history(wallet, options):
|
|||
|
||||
def s():
|
||||
return ',' if options.csv else ' '
|
||||
def sat_to_str(sat):
|
||||
return '%.8f'%(sat/1e8)
|
||||
def sat_to_str_p(sat):
|
||||
return '%+.8f'%(sat/1e8)
|
||||
def sat_to_str_na(sat):
|
||||
if sat == 0:
|
||||
return "N/A "
|
||||
else:
|
||||
return '%.8f'%(sat/1e8)
|
||||
return btc.sat_to_str(sat)
|
||||
def skip_n1(v):
|
||||
return '% 2s'%(str(v)) if v != -1 else ' #'
|
||||
def skip_n1_btc(v):
|
||||
return sat_to_str(v) if v != -1 else '#' + ' '*10
|
||||
return btc.sat_to_str(v) if v != -1 else '#' + ' '*10
|
||||
def print_row(index, time, tx_type, amount, delta, balance, cj_n,
|
||||
total_fees, utxo_count, mixdepth_src, mixdepth_dst, txid):
|
||||
data = [index, datetime.fromtimestamp(time).strftime("%Y-%m-%d %H:%M"),
|
||||
tx_type, sat_to_str(amount), sat_to_str_p(delta),
|
||||
sat_to_str(balance), skip_n1(cj_n), sat_to_str_na(total_fees),
|
||||
tx_type, btc.sat_to_str(amount), btc.sat_to_str_p(delta),
|
||||
btc.sat_to_str(balance), skip_n1(cj_n), sat_to_str_na(total_fees),
|
||||
'% 3d' % utxo_count, skip_n1(mixdepth_src), skip_n1(mixdepth_dst)]
|
||||
if options.verbosity % 2 == 0: data += [txid]
|
||||
jmprint(s().join(map('"{}"'.format, data)), "info")
|
||||
|
|
@ -870,8 +866,8 @@ def wallet_fetch_history(wallet, options):
|
|||
include_disabled=True).values())
|
||||
if balance + unconfirmed_balance != total_wallet_balance:
|
||||
jmprint(('BUG ERROR: wallet balance (%s) does not match balance from ' +
|
||||
'history (%s)') % (sat_to_str(total_wallet_balance),
|
||||
sat_to_str(balance)))
|
||||
'history (%s)') % (btc.sat_to_str(total_wallet_balance),
|
||||
btc.sat_to_str(balance)))
|
||||
wallet_utxo_count = sum(map(len, wallet.get_utxos_by_mixdepth(
|
||||
include_disabled=True, hexfmt=False).values()))
|
||||
if utxo_count + unconfirmed_utxo_count != wallet_utxo_count:
|
||||
|
|
@ -879,7 +875,7 @@ def wallet_fetch_history(wallet, options):
|
|||
'history (%s)') % (wallet_utxo_count, utxo_count))
|
||||
|
||||
if unconfirmed_balance != 0:
|
||||
jmprint('unconfirmed balance change = %s BTC' % sat_to_str(unconfirmed_balance))
|
||||
jmprint('unconfirmed balance change = %s BTC' % btc.sat_to_str(unconfirmed_balance))
|
||||
|
||||
# wallet-tool.py prints return value, so return empty string instead of None here
|
||||
return ''
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ import sys, datetime, os, logging
|
|||
import platform, json, threading, time
|
||||
import qrcode
|
||||
|
||||
from decimal import Decimal
|
||||
from PySide2 import QtCore
|
||||
|
||||
from PySide2.QtGui import *
|
||||
|
|
@ -83,8 +82,6 @@ from qtsupport import ScheduleWizard, TumbleRestartWizard, config_tips,\
|
|||
|
||||
|
||||
from twisted.internet import task
|
||||
def satoshis_to_amt_str(x):
|
||||
return str(Decimal(x)/Decimal('1e8')) + " BTC"
|
||||
|
||||
log = get_log()
|
||||
|
||||
|
|
@ -124,13 +121,13 @@ def checkAddress(parent, addr):
|
|||
def getSettingsWidgets():
|
||||
results = []
|
||||
sN = ['Recipient address', 'Number of counterparties', 'Mixdepth',
|
||||
'Amount in bitcoins (BTC)']
|
||||
'Amount (BTC or sat)']
|
||||
sH = ['The address you want to send the payment to',
|
||||
'How many other parties to send to; if you enter 4\n' +
|
||||
', there will be 5 participants, including you.\n' +
|
||||
'Enter 0 to send direct without coinjoin.',
|
||||
'The mixdepth of the wallet to send the payment from',
|
||||
'The amount IN BITCOINS to send.\n' +
|
||||
'The amount to send, either BTC (if contains dot) or satoshis.\n' +
|
||||
'If you enter 0, a SWEEP transaction\nwill be performed,' +
|
||||
' spending all the coins \nin the given mixdepth.']
|
||||
sT = [str, int, int, float]
|
||||
|
|
@ -591,9 +588,9 @@ class SpendTab(QWidget):
|
|||
note the callback includes the full prettified transaction,
|
||||
but currently not printing it for space reasons.
|
||||
"""
|
||||
mbinfo = ["Sending " + satoshis_to_amt_str(amount) + ",",
|
||||
mbinfo = ["Sending " + btc.amount_to_str(amount) + ",",
|
||||
"to: " + destaddr + ",",
|
||||
"Fee: " + satoshis_to_amt_str(fee) + ".",
|
||||
"Fee: " + btc.amount_to_str(fee) + ".",
|
||||
"Accept?"]
|
||||
reply = JMQtMessageBox(self, '\n'.join([m + '<p>' for m in mbinfo]),
|
||||
mbtype='question', title="Direct send")
|
||||
|
|
@ -614,7 +611,7 @@ class SpendTab(QWidget):
|
|||
destaddr = str(self.widgets[0][1].text())
|
||||
#convert from bitcoins (enforced by QDoubleValidator) to satoshis
|
||||
btc_amount_str = self.widgets[3][1].text()
|
||||
amount = int(Decimal(btc_amount_str) * Decimal('1e8'))
|
||||
amount = btc.amount_to_sat(btc_amount_str)
|
||||
makercount = int(self.widgets[1][1].text())
|
||||
mixdepth = int(self.widgets[2][1].text())
|
||||
if makercount == 0:
|
||||
|
|
@ -724,11 +721,9 @@ class SpendTab(QWidget):
|
|||
return
|
||||
offers, total_cj_fee = offers_fee
|
||||
total_fee_pc = 1.0 * total_cj_fee / self.taker.cjamount
|
||||
#Note this will be a new value if sweep, else same as previously entered
|
||||
btc_amount_str = satoshis_to_amt_str(self.taker.cjamount)
|
||||
|
||||
mbinfo = []
|
||||
mbinfo.append("Sending amount: " + btc_amount_str)
|
||||
mbinfo.append("Sending amount: " + btc.amount_to_str(self.taker.cjamount))
|
||||
mbinfo.append("to address: " + self.taker.my_cj_addr)
|
||||
mbinfo.append(" ")
|
||||
mbinfo.append("Counterparties chosen:")
|
||||
|
|
@ -746,8 +741,8 @@ class SpendTab(QWidget):
|
|||
return False
|
||||
mbinfo.append(k + ', ' + str(o['oid']) + ', ' + str(
|
||||
display_fee))
|
||||
mbinfo.append('Total coinjoin fee = ' + str(total_cj_fee) +
|
||||
' satoshis, or ' + str(float('%.3g' % (
|
||||
mbinfo.append('Total coinjoin fee = ' + btc.amount_to_str(total_cj_fee) +
|
||||
', or ' + str(float('%.3g' % (
|
||||
100.0 * total_fee_pc))) + '%')
|
||||
title = 'Check Transaction'
|
||||
if total_fee_pc * 100 > jm_single().config.getint("GUI",
|
||||
|
|
@ -842,7 +837,7 @@ class SpendTab(QWidget):
|
|||
def persistTxToHistory(self, addr, amt, txid):
|
||||
#persist the transaction to history
|
||||
with open(jm_single().config.get("GUI", "history_file"), 'ab') as f:
|
||||
f.write((','.join([addr, satoshis_to_amt_str(amt), txid,
|
||||
f.write((','.join([addr, btc.amount_to_btc_str(amt), txid,
|
||||
datetime.datetime.now(
|
||||
).strftime("%Y/%m/%d %H:%M:%S")])).encode('utf-8'))
|
||||
f.write(b'\n') #TODO: Windows
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ from twisted.python.log import startLogging
|
|||
from jmbase.support import get_log, set_logging_level, jmprint
|
||||
from cli_options import get_sendpayment_parser, get_max_cj_fee_values, \
|
||||
check_regtest
|
||||
import jmbitcoin as btc
|
||||
|
||||
log = get_log()
|
||||
|
||||
|
|
@ -64,9 +65,7 @@ def main():
|
|||
#of a single transaction
|
||||
sweeping = False
|
||||
if options.schedule == '':
|
||||
#note that sendpayment doesn't support fractional amounts, fractions throw
|
||||
#here.
|
||||
amount = int(args[1])
|
||||
amount = btc.amount_to_sat(args[1])
|
||||
if amount == 0:
|
||||
sweeping = True
|
||||
destaddr = args[2]
|
||||
|
|
@ -123,7 +122,7 @@ def main():
|
|||
if not options.p2ep and not options.pickorders and options.makercount != 0:
|
||||
maxcjfee = get_max_cj_fee_values(jm_single().config, options)
|
||||
log.info("Using maximum coinjoin fee limits per maker of {:.4%}, {} "
|
||||
"sat".format(*maxcjfee))
|
||||
"".format(maxcjfee[0], btc.amount_to_str(maxcjfee[1])))
|
||||
|
||||
log.debug('starting sendpayment')
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue