# Path: jmbase/jmbase/support.py
# def get_log():
#     """
#     provides joinmarket logging instance
#     :return: log instance
#     """
#     return log
# 
# def bintohex(b):
#     """Convert bytes to a hex string"""
#     return binascii.hexlify(b).decode('utf8')
# 
# def hexbin(func):
#     """ Decorator for functions of taker and maker receiving over
#     the wire AMP arguments that may be in hex or hextxid:n format
#     and converting all to binary.
#     Functions to which this decorator applies should have all arguments
#     be one of:
#     - hex string (keys), converted here to binary
#     - lists of keys or txid:n strings (converted here to binary, or
#       (txidbytes, n))
#     - lists of lists or dicts, to which these rules apply recursively.
#     - any other string (unchanged)
#     - dicts with keys as per above; values are altered recursively according
#       to the rules above.
#     """
#     @wraps(func)
#     def func_wrapper(inst, *args, **kwargs):
#         newargs = []
#         for arg in args:
#             if isinstance(arg, (list, tuple)):
#                 newargs.append(listchanger(arg))
#             elif isinstance(arg, dict):
#                 newargs.append(dictchanger(arg))
#             else:
#                 newargs.append(_convert(arg))
#         return func(inst, *newargs, **kwargs)
# 
#     return func_wrapper
# 
# Path: jmclient/jmclient/cryptoengine.py
# class EngineError(Exception):
#     pass
# 
# Path: jmclient/jmclient/schedule.py
# NO_ROUNDING = 16 #max btc significant figures not including LN


import base64
import pprint
import random
import jmbitcoin as btc
from typing import Any, NamedTuple
from twisted.internet import reactor, task
from jmclient.configure import jm_single, validate_address, get_interest_rate
from jmbase import get_log, bintohex, hexbin
from jmclient.support import (calc_cj_fee, fidelity_bond_weighted_order_choose, choose_orders,
                              choose_sweep_orders)
from jmclient.wallet import estimate_tx_fee, compute_tx_locktime, FidelityBondMixin
from jmclient.podle import generate_podle, get_podle_commitments
from jmclient.wallet_service import WalletService
from jmclient.fidelity_bond import FidelityBondProof
from .output import generate_podle_error_string
from .cryptoengine import EngineError
from .schedule import NO_ROUNDING
            try:
                if self.wallet_service.pubkey_has_script(
                        auth_pub, inp['script']):
                    break
            except EngineError as e:
                pass
        else:
            raise IoauthInputVerificationError([
                f"ERROR maker's ({nick}) authorising pubkey is not included "
                "in the transaction!"])

        total_input = sum([d['value'] for d in utxo_data])
        real_cjfee = calc_cj_fee(self.orderbook[nick]['ordertype'],
                                 self.orderbook[nick]['cjfee'],
                                 self.cjamount)
        change_amount = (total_input - self.cjamount -
                         self.orderbook[nick]['txfee'] + real_cjfee)

        # certain malicious and/or incompetent liquidity providers send
        # inputs totalling less than the coinjoin amount! this leads to
        # a change output of zero satoshis; this counterparty must be removed.
        if change_amount < jm_single().DUST_THRESHOLD:
            raise IoauthInputVerificationError([
                f"ERROR counterparty requires sub-dust change. nick={nick} "
                f"totalin={total_input:d} cjamount={self.cjamount:d} "
                f"change={change_amount:d}",
                f"Invalid change, too small, nick={nick}"])
        return self._MakerTxData(nick, utxo_data, total_input, change_amount,
                                 real_cjfee)


# Path: jmbase/jmbase/support.py
# def get_log():
#     """
#     provides joinmarket logging instance
#     :return: log instance
#     """
#     return log
# 
# def bintohex(b):
#     """Convert bytes to a hex string"""
#     return binascii.hexlify(b).decode('utf8')
# 
# def hexbin(func):
#     """ Decorator for functions of taker and maker receiving over
#     the wire AMP arguments that may be in hex or hextxid:n format
#     and converting all to binary.
#     Functions to which this decorator applies should have all arguments
#     be one of:
#     - hex string (keys), converted here to binary
#     - lists of keys or txid:n strings (converted here to binary, or
#       (txidbytes, n))
#     - lists of lists or dicts, to which these rules apply recursively.
#     - any other string (unchanged)
#     - dicts with keys as per above; values are altered recursively according
#       to the rules above.
#     """
#     @wraps(func)
#     def func_wrapper(inst, *args, **kwargs):
#         newargs = []
#         for arg in args:
#             if isinstance(arg, (list, tuple)):
#                 newargs.append(listchanger(arg))
#             elif isinstance(arg, dict):
#                 newargs.append(dictchanger(arg))
#             else:
#                 newargs.append(_convert(arg))
#         return func(inst, *newargs, **kwargs)
# 
#     return func_wrapper
# 
# Path: jmclient/jmclient/cryptoengine.py
# class EngineError(Exception):
#     pass
# 
# Path: jmclient/jmclient/schedule.py
# NO_ROUNDING = 16 #max btc significant figures not including LN


# Path: jmclient/jmclient/taker.py
import base64
import pprint
import random
import jmbitcoin as btc
from typing import Any, NamedTuple
from twisted.internet import reactor, task
from jmclient.configure import jm_single, validate_address, get_interest_rate
from jmbase import get_log, bintohex, hexbin
from jmclient.support import (calc_cj_fee, fidelity_bond_weighted_order_choose, choose_orders,
                              choose_sweep_orders)
from jmclient.wallet import estimate_tx_fee, compute_tx_locktime, FidelityBondMixin
from jmclient.podle import generate_podle, get_podle_commitments
from jmclient.wallet_service import WalletService
from jmclient.fidelity_bond import FidelityBondProof
from .output import generate_podle_error_string
from .cryptoengine import EngineError
from .schedule import NO_ROUNDING

            try:
                if self.wallet_service.pubkey_has_script(
                        auth_pub, inp['script']):
                    break
            except EngineError as e:
                pass
        else:
            raise IoauthInputVerificationError([
                f"ERROR maker's ({nick}) authorising pubkey is not included "
                "in the transaction!"])

        total_input = sum([d['value'] for d in utxo_data])
        real_cjfee = calc_cj_fee(self.orderbook[nick]['ordertype'],
                                 self.orderbook[nick]['cjfee'],
                                 self.cjamount)
        change_amount = (total_input - self.cjamount -
                         self.orderbook[nick]['txfee'] + real_cjfee)

        # certain malicious and/or incompetent liquidity providers send
        # inputs totalling less than the coinjoin amount! this leads to
        # a change output of zero satoshis; this counterparty must be removed.
        if change_amount < jm_single().DUST_THRESHOLD:
            raise IoauthInputVerificationError([
                f"ERROR counterparty requires sub-dust change. nick={nick} "
                f"totalin={total_input:d} cjamount={self.cjamount:d} "
                f"change={change_amount:d}",
                f"Invalid change, too small, nick={nick}"])
        return self._MakerTxData(nick, utxo_data, total_input, change_amount,
                                 real_cjfee)


    @hexbin