mirror of
https://github.com/JoinMarket-Org/joinmarket-clientserver.git
synced 2026-08-15 12:50:57 +02:00
- update mktx() to allow optional locktime setting (and sequence) - add a mk_shuffled_tx method to the wallet module - add a P2EPTaker and P2EPMaker class (inherit from Taker, Maker) - add a -T option to sendpayment script for doing payjoins - add a receive_payjoin script for receivers. - add payjoin tests in jmclient/test/test_payjoin.py - add a custom utxo selection method select_one_utxo to support.py - support bech32 wallets (SegwitWallet, p2wpkh) with native=true in config POLICY for PayJoin and direct send (not Joinmarket CJ) - add a PayJoin.md usage guide in docs/ - include version bytes in pubkey message for forward compat - taker pays fees but controls size (utxo number and fee/kB) - add P2WPKH fee estimator - Enforce INFO level logging in payjoin - refactors regtest config settings into one place - bugfix: script_to_address vbyte argument is bytes not integer
125 lines
4.7 KiB
Python
125 lines
4.7 KiB
Python
#! /usr/bin/env python
|
|
from __future__ import (absolute_import, division,
|
|
print_function, unicode_literals)
|
|
from builtins import * # noqa: F401
|
|
"""A simple command line tool to create a bunch
|
|
of utxos from one (thus giving more potential commitments
|
|
for a Joinmarket user, although of course it may be useful
|
|
for other reasons).
|
|
"""
|
|
|
|
from pprint import pformat
|
|
from optparse import OptionParser
|
|
import jmbitcoin as btc
|
|
from jmbase import get_log, jmprint
|
|
from jmclient import load_program_config, estimate_tx_fee, jm_single,\
|
|
get_p2pk_vbyte, validate_address, get_utxo_info,\
|
|
validate_utxo_data, quit
|
|
|
|
|
|
log = get_log()
|
|
|
|
def sign(utxo, priv, destaddrs, segwit=True):
|
|
"""Sign a tx sending the amount amt, from utxo utxo,
|
|
equally to each of addresses in list destaddrs,
|
|
after fees; the purpose is to create a large
|
|
number of utxos. If segwit=True the (single) utxo is assumed to
|
|
be of type segwit p2sh/p2wpkh.
|
|
"""
|
|
results = validate_utxo_data([(utxo, priv)], retrieve=True, segwit=segwit)
|
|
if not results:
|
|
return False
|
|
assert results[0][0] == utxo
|
|
amt = results[0][1]
|
|
ins = [utxo]
|
|
# TODO extend to other utxo types
|
|
txtype = 'p2sh-p2wpkh' if segwit else 'p2pkh'
|
|
estfee = estimate_tx_fee(1, len(destaddrs), txtype=txtype)
|
|
outs = []
|
|
share = int((amt - estfee) / len(destaddrs))
|
|
fee = amt - share*len(destaddrs)
|
|
assert fee >= estfee
|
|
log.info("Using fee: " + str(fee))
|
|
for i, addr in enumerate(destaddrs):
|
|
outs.append({'address': addr, 'value': share})
|
|
unsigned_tx = btc.mktx(ins, outs)
|
|
amtforsign = amt if segwit else None
|
|
return btc.sign(unsigned_tx, 0, btc.from_wif_privkey(
|
|
priv, vbyte=get_p2pk_vbyte()), amount=amtforsign)
|
|
|
|
def main():
|
|
parser = OptionParser(
|
|
usage=
|
|
'usage: %prog [options] utxo destaddr1 destaddr2 ..',
|
|
description="For creating multiple utxos from one (for commitments in JM)."
|
|
"Provide a utxo in form txid:N that has some unspent coins;"
|
|
"Specify a list of destination addresses and the coins will"
|
|
"be split equally between them (after bitcoin fees)."
|
|
|
|
"You'll be prompted to enter the private key for the utxo"
|
|
"during the run; it must be in WIF compressed format."
|
|
"After the transaction is completed, the utxo strings for"
|
|
|
|
"the new outputs will be shown."
|
|
"Note that these utxos will not be ready for use as external"
|
|
|
|
"commitments in Joinmarket until 5 confirmations have passed."
|
|
" BE CAREFUL about handling private keys!"
|
|
" Don't do this in insecure environments."
|
|
" Works only with p2pkh ('1') or p2sh-p2wpkh (segwit '3')"
|
|
" utxos - set segwit=False in the POLICY section of"
|
|
" joinmarket.cfg for the former."
|
|
)
|
|
parser.add_option(
|
|
'-v',
|
|
'--validate-utxos',
|
|
action='store_true',
|
|
dest='validate',
|
|
help='validate the utxos and pubkeys provided against the blockchain',
|
|
default=False
|
|
)
|
|
parser.add_option(
|
|
'-o',
|
|
'--validate-only',
|
|
action='store_true',
|
|
dest='vonly',
|
|
help='only validate the provided utxos (file or command line), not add',
|
|
default=False
|
|
)
|
|
parser.add_option(
|
|
'-n',
|
|
'--non-segwit-input',
|
|
action='store_true',
|
|
dest='nonsegwit',
|
|
help='input is p2pkh ("1" address), not segwit; if not used, input is assumed to be segwit type.',
|
|
default=False
|
|
)
|
|
(options, args) = parser.parse_args()
|
|
load_program_config()
|
|
if len(args) < 2:
|
|
quit(parser, 'Invalid syntax')
|
|
u = args[0]
|
|
priv = input(
|
|
'input private key for ' + u + ', in WIF compressed format : ')
|
|
u, priv = get_utxo_info(','.join([u, priv]))
|
|
if not u:
|
|
quit(parser, "Failed to parse utxo info: " + u)
|
|
destaddrs = args[1:]
|
|
for d in destaddrs:
|
|
if not validate_address(d):
|
|
quit(parser, "Address was not valid; wrong network?: " + d)
|
|
txsigned = sign(u, priv, destaddrs, segwit = not options.nonsegwit)
|
|
if not txsigned:
|
|
log.info("Transaction signing operation failed, see debug messages for details.")
|
|
return
|
|
log.debug("Got signed transaction:\n" + txsigned)
|
|
log.debug("Deserialized:")
|
|
log.debug(pformat(btc.deserialize(txsigned)))
|
|
if input('Would you like to push to the network? (y/n):')[0] != 'y':
|
|
log.info("You chose not to broadcast the transaction, quitting.")
|
|
return
|
|
jm_single().bc_interface.pushtx(txsigned)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
jmprint('done', "success")
|