#!/usr/bin/env python3 import asyncio from optparse import OptionParser import sys import jmclient # noqa: F401 install asyncioreactor from twisted.internet import reactor from jmclient.scripts_support import wrap_main, finalize_main_task from jmbase import get_log, jmprint from jmclient import jm_single, load_program_config, \ WalletService, open_test_wallet_maybe, get_wallet_path, check_regtest, \ add_base_options, JMBIP78ReceiverManager, start_reactor, \ check_and_start_tor from jmbase.support import EXIT_FAILURE, EXIT_ARGERROR from jmbitcoin import amount_to_sat jlog = get_log() async def receive_payjoin_main(): parser = OptionParser(usage='usage: %prog [options] [wallet file] [amount-to-receive]') add_base_options(parser) parser.add_option('-P', '--hs-port', action='store', type='int', dest='hsport', default=80, help='port on which to serve the ephemeral hidden service.') parser.add_option('-g', '--gap-limit', action='store', type="int", dest='gaplimit', default=6, help='gap limit for wallet, default=6') parser.add_option('-m', '--mixdepth', action='store', type='int', dest='mixdepth', default=0, help="mixdepth to source coins from") parser.add_option('-a', '--amtmixdepths', action='store', type='int', dest='amtmixdepths', help='number of mixdepths in wallet, default 5', default=5) (options, args) = parser.parse_args() if len(args) < 2: parser.error('Needs a wallet, and a receiving amount in bitcoins or satoshis') sys.exit(EXIT_ARGERROR) wallet_name = args[0] try: # amount is stored internally in sats, but will be decimal in URL. bip78_amount = amount_to_sat(args[1]) except: parser.error("Invalid receiving amount passed: " + bip78_amount) sys.exit(EXIT_FAILURE) if bip78_amount < 0: parser.error("Receiving amount must be a positive number") sys.exit(EXIT_FAILURE) load_program_config(config_path=options.datadir) check_and_start_tor() check_regtest() wallet_path = get_wallet_path(wallet_name, None) max_mix_depth = max([options.mixdepth, options.amtmixdepths - 1]) wallet = await open_test_wallet_maybe( wallet_path, wallet_name, max_mix_depth, wallet_password_stdin=options.wallet_password_stdin, gap_limit=options.gaplimit) wallet_service = WalletService(wallet) while not wallet_service.synced: wallet_service.sync_wallet(fast=not options.recoversync) wallet_service.startService() # having enforced wallet sync, we can check if we have coins # to do payjoin in the mixdepth if wallet_service.get_balance_by_mixdepth(minconfs=1)[options.mixdepth] == 0: jlog.error("Cannot do payjoin from mixdepth " + str( options.mixdepth) + ", no confirmed coins. Shutting down.") sys.exit(EXIT_ARGERROR) receiver_manager = JMBIP78ReceiverManager(wallet_service, options.mixdepth, bip78_amount, options.hsport) await receiver_manager.async_init(wallet_service, options.mixdepth, bip78_amount) reactor.callWhenRunning(receiver_manager.initiate) nodaemon = jm_single().config.getint("DAEMON", "no_daemon") daemon = True if nodaemon == 1 else False dhost = jm_single().config.get("DAEMON", "daemon_host") dport = jm_single().config.getint("DAEMON", "daemon_port") # JM is default, so must be switched off explicitly in this call: start_reactor(dhost, dport, bip78=True, jm_coinjoin=False, daemon=daemon) @wrap_main async def _main(): await receive_payjoin_main() jmprint('done') if __name__ == "__main__": asyncio_loop = asyncio.get_event_loop() main_task = asyncio_loop.create_task(_main()) reactor.run() finalize_main_task(main_task)