import argparse
import ast
import base64
import copy
import datetime
import json
import logging
import sys
import time
from decimal import Decimal
from functools import wraps

from ecdsa import BadSignatureError

from unetschema.claim import ClaimDict
from unetschema.decode import smart_decode
from unetschema.error import DecodeError
from unetschema.signer import SECP256k1, get_signer
from unetschema.uri import URIParseError, parse_unet_uri

from uwallet import __version__
from uwallet.contacts import Contacts
from uwallet.constants import COIN, TYPE_ADDRESS, TYPE_CLAIM, TYPE_SUPPORT, TYPE_UPDATE
from uwallet.constants import RECOMMENDED_CLAIMTRIE_HASH_CONFIRMS, MAX_BATCH_QUERY_SIZE
from uwallet.constants import MAX_TRANSFER_FEE,MIN_TRANSFER_FEE
from uwallet.constants import BINDING_FEE, PLATFORM_ADDRESS
from uwallet.hashing import Hash, hash_160
from uwallet.claims import verify_proof
from uwallet.ulord import hash_160_to_bc_address, is_address, decode_claim_id_hex
from uwallet.ulord import encode_claim_id_hex, encrypt_message, public_key_from_private_key
from uwallet.ulord import claim_id_hash, verify_message
from uwallet.base import base_decode
from uwallet.transaction import Transaction
from uwallet.transaction import decode_claim_script, deserialize as deserialize_transaction
from uwallet.transaction import get_address_from_output_script, script_GetOp
from uwallet.errors import InvalidProofError, NotEnoughFunds, InvalidTtransferFee
from uwallet.util import format_satoshis, rev_hex
from uwallet.mnemonic import Mnemonic

from uwallet import gl

log = logging.getLogger(__name__)

known_commands = {}
ADDRESS_LENGTH = 25
MAX_PAGE_SIZE = 500


# Format amount to be decimal encoded string
# Format value to be hex encoded string
def format_amount_value(obj):
    if isinstance(obj, dict):
        for k, v in obj.iteritems():
            if k == 'amount' or k == 'effective_amount':
                if not isinstance(obj[k], float):
                    obj[k] = float(obj[k]) / float(COIN)
            elif k == 'supports' and isinstance(v, list):
                obj[k] = [{'txid': txid, 'nout': nout, 'amount': float(amount) / float(COIN)}
                          for (txid, nout, amount) in v]
            elif isinstance(v, (list, dict)):
                obj[k] = format_amount_value(v)
    elif isinstance(obj, list):
        obj = [format_amount_value(o) for o in obj]
    return obj


class Command(object):
    def __init__(self, func, s):
        self.name = func.__name__
        self.requires_network = 'n' in s
        self.requires_wallet = 'w' in s
        self.requires_password = 'p' in s
        self.description = func.__doc__
        self.help = self.description.split('.')[0] if self.description else None
        varnames = func.func_code.co_varnames[1:func.func_code.co_argcount]
        self.defaults = func.func_defaults
        if self.defaults:
            n = len(self.defaults)
            self.params = list(varnames[:-n])
            self.options = list(varnames[-n:])
        else:
            self.params = list(varnames)
            self.options = []
            self.defaults = []


def command(s):
    def decorator(func):
        global known_commands
        name = func.__name__
        known_commands[name] = Command(func, s)

        @wraps(func)
        def func_wrapper(*args, **kwargs):
            return func(*args, **kwargs)

        return func_wrapper

    return decorator


class Commands(object):
    def __init__(self, config, wallet, network, callback=None, password=None, new_password=None):
        self.config = config
        self.wallet = wallet
        self.network = network
        self._callback = callback
        self._password = password
        self.new_password = new_password
        self.contacts = Contacts(self.config)

    def _run(self, method, args, password_getter):
        print "debug:Is this function running? "
        cmd = known_commands[method]
        if cmd.requires_password and self.wallet.use_encryption:
            self._password = apply(password_getter, ())
        f = getattr(self, method)
        result = f(*args)
        self._password = None
        if self._callback:
            apply(self._callback, ())
        return result

    @command('')
    def haswallet(self):
        """Is there a wallet?"""
        raise BaseException('Not a JSON-RPC command')

    @command('')
    def haspassword(self):
        """Is there a wallet?"""
        raise BaseException('Not a JSON-RPC command')

    @command('')
    def daemonisrunning(self):
        """Daemon is running"""
        raise BaseException('Not a JSON-RPC command')

    @command('')
    def commands(self):
        """List of commands"""
        return ' '.join(sorted(known_commands.keys()))

    @command('')
    def create(self):
        """Create a new wallet"""
        raise BaseException('Not a JSON-RPC command')

    @command('wn')
    def restore(self, text):
        """Restore a wallet from text. Text can be a seed phrase, a master
        public key, a master private key, a list of bitcoin addresses
        or bitcoin private keys. If you want to be prompted for your
        seed, type '?' or ':' (concealed) """
        raise BaseException('Not a JSON-RPC command')

    @command('w')
    def deseed(self):
        """Remove seed from wallet. This creates a seedless, watching-only
        wallet."""
        raise BaseException('Not a JSON-RPC command')

    @command('wp')
    def password(self):
        """Change wallet password. """
        self.wallet.update_password(self._password, self.new_password)
        self.wallet.storage.write()
        return {'password': self.wallet.use_encryption}

    @command('')
    def getconfig(self, key):
        """Return a configuration variable. """
        return self.config.get(key)

    @command('')
    def setconfig(self, key, value):
        """Set a configuration variable. 'value' may be a string or a Python expression."""
        try:
            value = ast.literal_eval(value)
        except:
            pass
        self.config.set_key(key, value)
        return True

    @command('')
    def make_seed(self, nbits=128, entropy=1, language=None):
        """Create a seed"""
        language = language or "en"
        s = Mnemonic(language).make_seed(nbits, custom_entropy=entropy)
        return s.encode('utf8')

    @command('')
    def check_seed(self, seed, entropy=1, language=None):
        """Check that a seed was generated with given entropy"""
        language = language or "en"
        return Mnemonic(language).check_seed(seed, entropy)

    @command('n')
    def getaddresshistory(self, address):
        """Return the transaction history of any address. Note: This is a
        walletless server query, results are not checked by SPV.
        """
        return self.network.synchronous_get(('blockchain.address.get_history', [address]))

    @command('w')
    def listunspent(self):
        """List unspent outputs. Returns the list of unspent transaction
        outputs in your wallet."""
        l = copy.deepcopy(self.wallet.get_spendable_coins(exclude_frozen=False))
        for i in l:
            v = i["value"]
            i["value"] = float(v) / float(COIN) if v is not None else None
        return l

    @command('n')
    def getaddressunspent(self, address):
        """Returns the UTXO list of any address. Note: This
        is a walletless server query, results are not checked by SPV.
        """
        return self.network.synchronous_get(('blockchain.address.listunspent', [address]))

    @command('n')
    def getutxoaddress(self, txid, pos):
        """Get the address of a UTXO. Note: This is a walletless server query, results are
        not checked by SPV.
        """
        r = self.network.synchronous_get(('blockchain.utxo.get_address', [txid, pos]))
        return {'address': r}

    @command('wp')
    def createrawtx(self, inputs, outputs, unsigned=False):
        """Create a transaction from json inputs. The syntax is similar to bitcoind."""
        coins = self.wallet.get_spendable_coins(exclude_frozen=False)
        tx_inputs = []
        for i in inputs:
            prevout_hash = i['txid']
            prevout_n = i['vout']
            for c in coins:
                if c['prevout_hash'] == prevout_hash and c['prevout_n'] == prevout_n:
                    self.wallet.add_input_info(c)
                    tx_inputs.append(c)
                    break
            else:
                raise BaseException('Transaction output not in wallet',
                                    prevout_hash + ":%d" % prevout_n)
        outputs = map(lambda x: (TYPE_ADDRESS, x[0], int(COIN * x[1])), outputs.items())
        tx = Transaction.from_io(tx_inputs, outputs)
        if not unsigned:
            self.wallet.sign_transaction(tx, self._password)
        return tx.as_dict()

    @command('wp')
    def signtransaction(self, tx, privkey=None):
        """Sign a transaction. The wallet keys will be used unless a private key is provided."""
        t = Transaction(tx)
        if privkey:
            pubkey = public_key_from_private_key(privkey)
            t.sign({pubkey: privkey})
        else:
            self.wallet.sign_transaction(t, self._password)
        return t.as_dict()

    @command('')
    def deserialize(self, tx):
        """Deserialize a serialized transaction"""
        return Transaction(tx).deserialize()

    @command('n')
    def broadcast(self, tx):
        """Broadcast a transaction to the network. """
        t = Transaction(tx)
        return self.network.synchronous_get(('blockchain.transaction.broadcast', [str(t)]))

    @command('')
    def createmultisig(self, num, pubkeys):
        """Create multisig address"""
        assert isinstance(pubkeys, list), (type(num), type(pubkeys))
        redeem_script = Transaction.multisig_script(pubkeys, num)
        address = hash_160_to_bc_address(hash_160(redeem_script.decode('hex')), 5)
        return {'address': address, 'redeemScript': redeem_script}

    @command('w')
    def freeze(self, address):
        """Freeze address. Freeze the funds at one of your wallet\'s addresses"""
        return self.wallet.set_frozen_state([address], True)

    @command('w')
    def unfreeze(self, address):
        """Unfreeze address. Unfreeze the funds at one of your wallet\'s address"""
        return self.wallet.set_frozen_state([address], False)

    @command('wp')
    def getprivatekeys(self, address):
        """
        Get private keys of addresses. You may pass a single wallet address,
        or a list of wallet addresses.
        """

        is_list = type(address) is list
        domain = address if is_list else [address]
        out = [self.wallet.get_private_key(address, self._password) for address in domain]
        return out if is_list else out[0]

    @command('w')
    def ismine(self, address):
        """Check if address is in wallet. Return true if and only address is in wallet"""
        return self.wallet.is_mine(address)

    @command('')
    def dumpprivkeys(self):
        """Deprecated."""
        return "This command is deprecated. Use a pipe instead: " \
               "'uwallet listaddresses | uwallet getprivatekeys - '"

    @command('')
    def validateaddress(self, address):
        """Check that an address is valid. """
        return is_address(address)

    @command('w')
    def getpubkeys(self, address):
        """Return the public keys for a wallet address. """
        return self.wallet.get_public_keys(address)

    @command('w')
    def getbalance(self, account=None, exclude_claimtrietx=False):
        """Return the balance of your wallet. """
        if account is None:
            c, u, x = self.wallet.get_balance(exclude_claimtrietx=exclude_claimtrietx)
        else:
            c, u, x = self.wallet.get_account_balance(account, exclude_claimtrietx)
        out = {"confirmed": str(Decimal(c) / COIN)}
        if u:
            out["unconfirmed"] = str(Decimal(u) / COIN)
        if x:
            out["unmatured"] = str(Decimal(x) / COIN)
        return out

    @command('n')
    def getaddressbalance(self, address):
        """Return the balance of any address. Note: This is a walletless
        server query, results are not checked by SPV.
        """
        out = self.network.synchronous_get(('blockchain.address.get_balance', [address]))
        out["confirmed"] = str(Decimal(out["confirmed"]) / COIN)
        out["unconfirmed"] = str(Decimal(out["unconfirmed"]) / COIN)
        return out

    @command('n')
    def getproof(self, address):
        """Get Merkle branch of an address in the UTXO set"""
        p = self.network.synchronous_get(('blockchain.address.get_proof', [address]))
        out = []
        for i, s in p:
            out.append(i)
        return out

    @command('n')
    def getmerkle(self, txid, height):
        """Get Merkle branch of a transaction included in a block. Electrum
        uses this to verify transactions (Simple Payment Verification)."""
        return self.network.synchronous_get(
            ('blockchain.transaction.get_merkle', [txid, int(height)]))

    @command('n')
    def getservers(self):
        """Return the list of available servers"""
        while not self.network.is_up_to_date():
            time.sleep(0.1)
        return self.network.get_servers()

    @command('')
    def version(self):
        """Return the version of uwallet."""
        return __version__

    @command('w')
    def getmpk(self):
        """Get master public key. Return your wallet\'s master public key(s)"""
        return self.wallet.get_master_public_keys()

    @command('wp')
    def getmasterprivate(self):
        """Get master private key. Return your wallet\'s master private key"""
        return str(self.wallet.get_master_private_key(self.wallet.root_name, self._password))

    @command('wp')
    def getseed(self):
        """Get seed phrase. Print the generation seed of your wallet."""
        s = self.wallet.get_mnemonic(self._password)
        return s.encode('utf8')

    @command('wp')
    def importprivkey(self, privkey):
        """Import a private key. """
        try:
            addr = self.wallet.import_key(privkey, self._password)
            out = "Keypair imported: " + addr
        except Exception as e:
            out = "Error: " + str(e)
        return out

    def _resolver(self, x):
        if x is None:
            return None
        out = self.contacts.resolve(x)
        if out.get('type') == 'openalias' and self.nocheck is False and out.get(
                'validated') is False:
            raise BaseException('cannot verify alias', x)
        return out['address']

    @command('n')
    def sweep(self, privkey, destination, tx_fee=None, nocheck=False):
        """Sweep private keys. Returns a transaction that spends UTXOs from
        privkey to a destination address. The transaction is not
        broadcasted."""
        privkeys = privkey if type(privkey) is list else [privkey]
        self.nocheck = nocheck
        dest = self._resolver(destination)
        if tx_fee is None:
            tx_fee = 0.0001
        fee = int(Decimal(tx_fee) * COIN)
        return Transaction.sweep(privkeys, self.network, dest, fee)

    @command('wp')
    def signmessage(self, address, message):
        """Sign a message with a key. Use quotes if your message contains
        whitespaces"""
        sig = self.wallet.sign_message(address, message, self._password)
        return base64.b64encode(sig)

    @command('')
    def verifymessage(self, address, signature, message):
        """Verify a signature."""
        sig = base64.b64decode(signature)
        return verify_message(address, sig, message)

    def _mktx(self, outputs, fee, change_addr, domain, nocheck, unsigned, claim_name=None,
              claim_val=None,
              abandon_txid=None, claim_id=None):
        self.nocheck = nocheck
        change_addr = self._resolver(change_addr)
        domain = None if domain is None else map(self._resolver, domain)
        fee = None if fee is None else int(COIN * Decimal(fee))
        final_outputs = []
        for address, amount in outputs:
            address = self._resolver(address)
            # assert self.wallet.is_mine(address)
            if amount == '!':
                assert len(outputs) == 1
                inputs = self.wallet.get_spendable_coins(domain)
                amount = sum(map(lambda x: x['value'], inputs))
                if fee is None:
                    for i in inputs:
                        self.wallet.add_input_info(i)
                    output = (TYPE_ADDRESS, address, amount)
                    dummy_tx = Transaction.from_io(inputs, [output])
                    fee_per_kb = self.wallet.fee_per_kb(self.config)
                    fee = dummy_tx.estimated_fee(self.wallet.relayfee(), fee_per_kb)
                    if fee >= MAX_TRANSFER_FEE:
                        print "There is too much data for a single transaction, exceeding the maximum limit.\
                              Please integrate fragmented UTXO first."
                        raise InvalidTtransferFee
                amount -= fee
            else:
                amount = int(COIN * Decimal(amount))
            txout_type = TYPE_ADDRESS
            val = address
            if claim_name is not None and claim_val is not None and claim_id is not None\
                    and abandon_txid is not None:
                assert len(outputs) == 1
                txout_type |= TYPE_UPDATE
                val = ((claim_name, claim_id, claim_val), val)
            elif claim_name is not None and claim_id is not None:
                assert len(outputs) == 1
                txout_type |= TYPE_SUPPORT
                val = ((claim_name, claim_id), val)
            elif claim_name is not None and claim_val is not None:
                # Try to modify the structure of the published resources. --JustinQP
                # assert len(outputs) == 1   
                assert len(outputs) == 2
                txout_type |= TYPE_CLAIM
                val = ((claim_name, claim_val), val)
            final_outputs.append((txout_type, val, amount))

        coins = self.wallet.get_spendable_coins(domain, abandon_txid=abandon_txid)
        tx = self.wallet.make_unsigned_transaction(coins, final_outputs, self.config, fee,
                                                   change_addr,
                                                   abandon_txid=abandon_txid)
        str(tx)  # this serializes
        if not unsigned:
            self.wallet.sign_transaction(tx, self._password)

        return tx

    @command('wp')
    def getnewaddress(self):
        """Get a new receive address."""
        return self.wallet.create_new_address()

    @command('wp')
    def getunusedaddress(self, account=None):
        addr = self.wallet.get_unused_address(account)
        if addr is None:
            addr = self.wallet.create_new_address()
        return addr

    @command('wp')
    def getnewaddress(self):
        """Get a new receive address."""
        return self.wallet.create_new_address()

    @command('wp')
    def getleastusedchangeaddress(self, account=None):
        return self.wallet.get_least_used_address(account, for_change=True)

    @command('wp')
    def getleastusedaddress(self, account=None):
        return self.wallet.get_least_used_address(account)

    @command('wp')
    def payto(self, destination, amount, tx_fee=None, from_addr=None, change_addr=None,
              nocheck=False, unsigned=False):
        """Create a raw transaction. """
        domain = [from_addr] if from_addr else None
        tx = self._mktx([(destination, amount)], tx_fee, change_addr, domain, nocheck, unsigned)
        return tx.as_dict()

    @command('wpn')
    def paytoandsend(self, destination, amount, tx_fee=None, from_addr=None, change_addr=None,
                     nocheck=False, unsigned=False):
        """Create and broadcast transaction. """
        domain = [from_addr] if from_addr else None
        tx = self._mktx([(destination, amount)], tx_fee, change_addr, domain, nocheck, unsigned)
        return self.network.synchronous_get(('blockchain.transaction.broadcast', [str(tx)]))

    @command('wpn')
    def testpaytoandsend(self, destination, amount, tx_fee=None, from_addr=None, change_addr=None,
                     nocheck=False, unsigned=False):
        """The purpose is to test generate txid. --JustinQP """
        domain = [from_addr] if from_addr else None
        tx = self._mktx([(destination, amount)], tx_fee, change_addr, domain, nocheck, unsigned)
        self.network.synchronous_get(('blockchain.transaction.broadcast', [str(tx)]))
        raw = str(tx)
        tx_double_hash = sha256(sha256(raw))
        return  tx_double_hash[::-1].encode('hex')

    @command('w')
    def waitfortxinwallet(self, txid, timeout=30):
        """
        wait for tx with txid to appear in wallet for timeout seconds
        return True, if txid appears within timeout, return False otherwise
        """
        start_time = time.time()
        while start_time - time.time() < timeout:
            if txid in self.wallet.transactions:
                return True
            time.sleep(0.2)
        return False

    @command('wpn')
    def sendclaimtoaddress(self, claim_id, destination, amount, tx_fee=None, change_addr=None,
                           broadcast=True, skip_validate_schema=None):
        claims = self.getnameclaims(raw=True, include_supports=False, claim_id=claim_id,
                                    skip_validate_signatures=True)
        if len(claims) > 1:
            return {"success": False, 'reason': 'more than one claim that matches'}
        elif len(claims) == 0:
            return {"success": False, 'reason': 'claim not found', 'claim_id': claim_id}
        else:
            claim = claims[0]

        txid = claim['txid']
        nout = claim['nout']
        claim_name = claim['name']
        claim_val = claim['value']
        # claim_val =  base64_to_json(claim['value']).encode('hex')
        certificate_id = None
        if not skip_validate_schema:
            decoded = smart_decode(claim_val)
            if self.cansignwithcertificate(decoded.certificate_id):
                certificate_id = decoded.certificate_id
        return self.update(claim_name, claim_val, amount=amount, certificate_id=certificate_id,
                           claim_id=claim_id, txid=txid, nout=nout, broadcast=broadcast,
                           claim_addr=destination, tx_fee=tx_fee, change_addr=change_addr,
                           raw=False, skip_validate_schema=skip_validate_schema)


    @command('wp')
    def paytomany(self, outputs, tx_fee=None, from_addr=None, change_addr=None, nocheck=False,
                  unsigned=False):
        """Create a multi-output transaction. """
        domain = [from_addr] if from_addr else None
        tx = self._mktx(outputs, tx_fee, change_addr, domain, nocheck, unsigned)
        return tx.as_dict()

    @command('wp')
    def paytomanyandsend(self, outputs, tx_fee=None, from_addr=None, change_addr=None,
                         nocheck=False, unsigned=False):
        """Create and broadcast a multi-output transaction. """
        domain = [from_addr] if from_addr else None
        tx = self._mktx(outputs, tx_fee, change_addr, domain, nocheck, unsigned)
        return self.network.synchronous_get(('blockchain.transaction.broadcast', [str(tx)]))

    @command('w')
    def claimhistory(self):

        claim_amt = dict()
        def get_info_dict(name, claim_id, nout, txo, value, tx_type):
            amount = float(Decimal(txo[2]) / Decimal(COIN))

            if tx_type == "claim":
                amount = -1 * amount
                claim_amt[claim_id] = amount
            elif tx_type == "support" and value < 0:
                amount = -1 * amount
            elif tx_type == "update":
                abs_amount = abs(amount)
                if claim_id in claim_amt:
                    # the previous update or claim is known already
                    abs_prev_amount = abs(claim_amt[claim_id])
                    claim_amt[claim_id] = amount
                    amount = abs_prev_amount - abs_amount
                else:
                    # this is a claim that was sent to us via an update transaction
                    amount = abs_amount
                    claim_amt[claim_id] = abs_amount
            return {
                'claim_name': name,
                'claim_id': claim_id,
                'nout': nout,
                'balance_delta': amount,
                'amount': float(Decimal(txo[2]) / Decimal(COIN)),
                'address': txo[1][1]
            }

        history = self.history()
        results = []

        for history_result in history:
            txid = history_result['txid']
            tx = self.wallet.transactions[txid]
            tx_outs = tx.outputs()

            support_infos = []
            update_infos = []
            claim_infos = []

            for nout, tx_out in enumerate(tx_outs):
                if tx_out[0] & TYPE_SUPPORT:
                    claim_name, claim_id = tx_out[1][0]
                    claim_id = encode_claim_id_hex(claim_id)
                    support_infos.append(get_info_dict(claim_name, claim_id, nout, tx_out,
                        history_result['value'], tx_type="support"))
                elif tx_out[0] & TYPE_UPDATE:
                    claim_name, claim_id, claim_value = tx_out[1][0]
                    claim_id = encode_claim_id_hex(claim_id)
                    update_infos.append(get_info_dict(claim_name, claim_id, nout, tx_out,
                        history_result['value'], tx_type="update"))
                elif tx_out[0] & TYPE_CLAIM:
                    claim_name, claim_value = tx_out[1][0]
                    claim_id = claim_id_hash(rev_hex(tx.hash()).decode('hex'), nout)
                    claim_id = encode_claim_id_hex(claim_id)
                    claim_infos.append(get_info_dict(claim_name, claim_id, nout, tx_out,
                        history_result['value'], tx_type="claim"))

            result = history_result
            result['support_info'] = support_infos
            result['update_info'] = update_infos
            result['claim_info'] = claim_infos
            results.append(result)
        return results

    @command('wn')
    def tiphistory(self):
        claim_ids_to_check = []
        results = []

        claim_history = self.claimhistory()
        for h in claim_history:
            for supported in h['support_info']:
                claim_ids_to_check.append(supported['claim_id'])

        claims = self.getclaimsbyids(claim_ids_to_check)

        for h in claim_history:
            support_info = []
            for supported in h['support_info']:
                claim_ids_to_check.append(supported['claim_id'])
                claim = claims.get(supported['claim_id'])
                if claim:
                    if supported['address'] == claim['address']:
                        supported['is_tip'] = True
                    else:
                        supported['is_tip'] = False
                    support_info.append(supported)
            h['support_info'] = support_info
            results.append(h)

        return results

    @command('w')
    def transactionfee(self, txid):
        """
        Get the fee for a transaction by txid
        """

        if txid in self.wallet.transactions:
            tx = self.wallet.transactions[txid]
        else:
            return {'error': 'transaction is not in local history'}
        fee = 0

        for tx_in in tx.inputs():
            # add up the amounts for the txos used as inputs
            if tx_in['prevout_hash'] in self.wallet.transactions:
                spent_tx = self.wallet.transactions[tx_in['prevout_hash']]
                fee += spent_tx.outputs()[tx_in['prevout_n']][2]
            else:
                # TODO: look up and save the transaction
                return float(Decimal(tx.fee_for_size(self.wallet.relayfee(),
                                                     self.wallet.fee_per_kb(self.config),
                                                     tx.estimated_size())) / Decimal(COIN))
        return float(Decimal(fee - tx.output_value()) / Decimal(COIN))

    @command('w')
    def history(self):
        """Wallet history. Returns the transaction history of your wallet."""

        out = []
        for tx_hash, confirms, value, timestamp, balance in self.wallet.get_history():
            try:
                time_str = datetime.datetime.fromtimestamp(timestamp).isoformat(' ')[:-3]
            except Exception:
                time_str = "----"

            result = {
                'txid': tx_hash,
                'fee': self.transactionfee(tx_hash),
                'timestamp': timestamp,
                'date': "%16s" % time_str,
                'value': float(value) / float(COIN) if value is not None else None,
                'confirmations': confirms
            }
            out.append(result)
        return out

    @command('w')
    def setlabel(self, key, label):
        """Assign a label to an item. Item may be a bitcoin address or a
        transaction ID"""
        self.wallet.set_label(key, label)

    @command('')
    def listcontacts(self):
        """Show your list of contacts"""
        return self.contacts

    @command('')
    def getalias(self, key):
        """Retrieve alias. Lookup in your list of contacts, and for an OpenAlias DNS record."""
        return self.contacts.resolve(key)

    @command('')
    def searchcontacts(self, query):
        """Search through contacts, return matching entries. """
        results = {}
        for key, value in self.contacts.items():
            if query.lower() in key.lower():
                results[key] = value
        return results

    @command('w')
    def listaddresses(self, receiving=False, change=False, show_labels=False, frozen=False,
                      unused=False, funded=False, show_balance=False):
        """
        List wallet addresses. Returns the list of all addresses in your wallet.
        Use optional arguments to filter the results.
        """

        out = []
        for addr in self.wallet.addresses(True):
            if frozen and not self.wallet.is_frozen(addr):
                continue
            if receiving and self.wallet.is_change(addr):
                continue
            if change and not self.wallet.is_change(addr):
                continue
            if unused and self.wallet.is_used(addr):
                continue
            if funded and self.wallet.is_empty(addr):
                continue
            item = addr
            if show_balance:
                item += ", " + format_satoshis(sum(self.wallet.get_addr_balance(addr)))
            if show_labels:
                item += ', ' + repr(self.wallet.labels.get(addr, ''))
            out.append(item)
        return out

    @command('w')
    def gettransaction(self, txid):
        """Retrieve a transaction in deserialized json format"""
        tx = self.wallet.transactions.get(txid) if self.wallet else None
        if tx is None and self.network:
            raw = self.network.synchronous_get(('blockchain.transaction.get', [txid]))
            if raw:
                tx = Transaction(raw)
            else:
                raise BaseException("Unknown transaction")
        return deserialize_transaction(str(tx))

    @command('')
    def encrypt(self, pubkey, message):
        """Encrypt a message with a public key. Use quotes if the message contains whitespaces."""
        return encrypt_message(message, pubkey)

    @command('wp')
    def decrypt(self, pubkey, encrypted):
        """Decrypt a message encrypted with a public key."""
        return self.wallet.decrypt_message(pubkey, encrypted, self._password)

    @command('n')
    def notify(self, address, URL):
        """Watch an address. Everytime the address changes, a http POST is sent to the URL."""

        def callback(x):
            import urllib2
            headers = {'content-type': 'application/json'}
            data = {'address': address, 'status': x.get('result')}
            try:
                req = urllib2.Request(URL, json.dumps(data), headers)
                response_stream = urllib2.urlopen(req)
                log.info('Got Response for %s' % address)
            except BaseException as e:
                log.error(str(e))

        self.network.send([('blockchain.address.subscribe', [address])], callback)
        return True

    def validate_claim_signature_and_get_channel_name(self, claim, certificate_claim,
                                                      claim_address, decoded_certificate=None):
        if not certificate_claim:
            return False, None
        certificate = decoded_certificate or smart_decode(certificate_claim['value'])
        if not isinstance(certificate, ClaimDict):
            raise TypeError("Certificate is not a ClaimDict: %s" % str(type(certificate)))
        if Commands._validate_signed_claim(claim, claim_address, certificate):
            return True, certificate_claim['name']
        return False, None

    def parse_and_validate_claim_result(self, claim_result, certificate=None, raw=False):
        if not claim_result or 'value' not in claim_result:
            return claim_result

        claim_result['decoded_claim'] = False
        decoded = None

        if not raw:
            claim_value = claim_result['value']
            try:

                # Because I did a base64 encoding when I wrote the transaction --JustinQP
                # claim_value_decoded = base64.b64decode(claim_value.decode('hex'))       
                # decoded = smart_decode(claim_value_decoded.encode('hex'))
                decoded = smart_decode(claim_value)
                claim_result['value'] = decoded.claim_dict
                claim_result['decoded_claim'] = True
            except DecodeError:
                pass

        if decoded:
            claim_result['has_signature'] = False
            if decoded.has_signature:
                if certificate is None:
                    log.info("fetching certificate to check claim signature")
                    certificate = self.getclaimbyid(decoded.certificate_id)
                    if not certificate:
                        log.warning('Certificate %s not found', decoded.certificate_id)
                claim_result['has_signature'] = True
                claim_result['signature_is_valid'] = False
                validated, channel_name = self.validate_claim_signature_and_get_channel_name(
                    decoded, certificate, claim_result['address'])
                claim_result['channel_name'] = channel_name
                if validated:
                    claim_result['signature_is_valid'] = True

        if 'height' in claim_result and claim_result['height'] is None:
            claim_result['height'] = -1

        if 'amount' in claim_result and not isinstance(claim_result['amount'], float):
            claim_result = format_amount_value(claim_result)

        return claim_result

    def offline_parse_and_validate_claim_result(self, claim_result, certificate, raw=False,
                                                decoded_claim=None, decoded_certificate=None,
                                                skip_validate_signatures=False):
        """
        Parse and validate a claim result from uwallet server

        Unlike  parse_and_validate_claim_result, this function does not
        send any queries to uwallet server. In the other function this
        is done to retrieve the certificate claim referenced by the signed
        claim.

        :param claim_result: a claim result from uwallet server
        :param certificate: a certificate result from uwallet server | None
        :param raw: bool
        :param decoded_claim: ClaimDict obtained from claim value
        :param decoded_certificate: ClaimDict
        :param skip_validate_signatures: bool, claim signature validation is not necessary for many
        local operations and adds significant overhead to the call, ie 2200 claims can be parsed
        in under 6 seconds without signature validation and just over a minute with it
        :return: formatted claim result
        """

        # TODO: remove the old parse_and_validate_claim_result function

        if not claim_result or 'value' not in claim_result:
            return claim_result

        claim_result['decoded_claim'] = False
        decoded = None

        if decoded_claim:
            if not isinstance(decoded_claim, ClaimDict):
                raise TypeError("Not given a ClaimDict: %s" % str(type(decoded_claim)))
        if decoded_certificate:
            if not isinstance(decoded_certificate, ClaimDict):
                raise TypeError("Not given a ClaimDict: %s" % str(type(decoded_certificate)))

        if not raw:
            claim_value = claim_result['value']
            if decoded_claim:
                decoded = decoded_claim
                claim_result['value'] = decoded.claim_dict
                claim_result['decoded_claim'] = True
            else:
                try:
                    decoded = smart_decode(claim_value)
                    claim_result['value'] = decoded.claim_dict
                    claim_result['decoded_claim'] = True
                except DecodeError:
                    pass

        if decoded:
            claim_result['has_signature'] = False
            if decoded.has_signature:
                claim_result['has_signature'] = True
                claim_result['signature_is_valid'] = False
                if not skip_validate_signatures:
                    validated, channel_name = self.validate_claim_signature_and_get_channel_name(
                        decoded, certificate, claim_result['address'])
                    claim_result['channel_name'] = channel_name
                    if validated:
                        claim_result['signature_is_valid'] = True
                else:
                    claim_result['signature_is_valid'] = None

        if 'height' in claim_result and claim_result['height'] is None:
            claim_result['height'] = -1

        if 'amount' in claim_result and not isinstance(claim_result['amount'], float):
            claim_result = format_amount_value(claim_result)

        return claim_result

    @staticmethod
    def _validate_signed_claim(claim, claim_address, certificate):
        if not claim.has_signature:
            raise Exception("Claim is not signed")
        if not base_decode(claim_address, ADDRESS_LENGTH, 58):
            raise Exception("Not given a valid claim address")
        try:
            if claim.validate_signature(claim_address, certificate.protobuf):
                return True
        except BadSignatureError:
            # print_msg("Signature for %s is invalid" % claim_id)
            return False
        except Exception as err:
            log.error("Signature for %s is invalid, reason: %s - %s", claim_address,
                      str(type(err)), err)
            return False
        return False

    @staticmethod
    def _verify_proof(name, claim_trie_root, result, height, depth):
        """
        Verify proof for name claim
        """

        def _build_response(name, value, claim_id, txid, n, amount, effective_amount,
                            claim_sequence, claim_address, supports):
            r = {
                'name': name,
                'value': value.encode('hex'),
                'claim_id': claim_id,
                'txid': txid,
                'nout': n,
                'amount': amount,
                'effective_amount': effective_amount,
                'height': height,
                'depth': depth,
                'claim_sequence': claim_sequence,
                'address': claim_address,
                'supports': supports
            }
            return r

        def _parse_proof_result(name, result):
            support_amount = sum([amt for (stxid, snout, amt) in result['supports']])
            supports = result['supports']
            if 'txhash' in result['proof'] and 'nOut' in result['proof']:
                if 'transaction' in result:
                    computed_txhash = Hash(result['transaction'].decode('hex'))[::-1].encode('hex')
                    tx = deserialize_transaction(result['transaction'])
                    nOut = result['proof']['nOut']
                    if result['proof']['txhash'] == computed_txhash:
                        if 0 <= nOut < len(tx['outputs']):
                            scriptPubKey = tx['outputs'][nOut]['scriptPubKey']
                            amount = tx['outputs'][nOut]['value']
                            effective_amount = amount + support_amount
                            decoded_script = [r for r in script_GetOp(scriptPubKey.decode('hex'))]
                            decode_out = decode_claim_script(decoded_script)
                            decode_address = get_address_from_output_script(
                                scriptPubKey.decode('hex'))
                            claim_address = decode_address[1][1]
                            claim_id = result['claim_id']
                            claim_sequence = result['claim_sequence']
                            if decode_out is False:
                                return {'error': 'failed to decode as claim script'}
                            n, script = decode_out
                            decoded_name, decoded_value = n.name, n.value
                            if decoded_name == name:
                                return _build_response(name, decoded_value, claim_id,
                                                       computed_txhash, nOut, amount,
                                                       effective_amount, claim_sequence,
                                                       claim_address, supports)
                            return {'error': 'name in proof did not match requested name'}
                        outputs = len(tx['outputs'])
                        return {'error': 'invalid nOut: %d (let(outputs): %d' % (nOut, outputs)}
                    return {'error': "computed txid did not match given transaction: %s vs %s" %
                                     (computed_txhash, result['proof']['txhash'])
                            }
                return {'error': "didn't receive a transaction with the proof"}
            return {'error': 'name is not claimed'}

        if 'proof' in result:
            try:
                verify_proof(result['proof'], claim_trie_root, name)
            except InvalidProofError:
                return {'error': "Proof was invalid"}
            return _parse_proof_result(name, result)
        else:
            return {'error': "proof not in result"}

    @command('n')
    def requestvalueforname(self, name, blockhash):
        """
        Request and return value of name with proof from uwallet server without verifying proof
        """

        if not name:
            return {'error': 'no name to request'}
        log.info('Requesting value for name: %s, blockhash: %s', name, blockhash)
        return self.network.synchronous_get(('blockchain.claimtrie.getvalue', [name, blockhash]))

    @command('n')
    def getvalueforname(self, name, raw=False):
        """
        Request value of name from uwallet server and verify its proof
        """

        height = self.network.get_local_height() - RECOMMENDED_CLAIMTRIE_HASH_CONFIRMS + 1
        block_header = self.network.blockchain.read_header(height)
        block_hash = self.network.blockchain.hash_header(block_header)
        response = self.requestvalueforname(name, block_hash)
        height, depth = None, None
        if response and 'height' in response:
            height = response['height']
            depth = self.network.get_server_height() - height
        result = Commands._verify_proof(name, block_header['claim_trie_root'], response,
                                        height, depth)
        return self.parse_and_validate_claim_result(result, raw=raw)

    @command('n')
    def getclaimbynameinchannel(self, uri, name, raw=False):
        """
        Get claim by name within a channel by uri
        """

        channel_claims = self.getclaimsinchannel(uri, raw)
        if 'error' in channel_claims:
            return channel_claims
        for claim in channel_claims:
            if claim['name'] == name:
                return claim
        return {'success': False, 'error': 'claim not found', 'name': name}

    @command('wn')
    def getdefaultcertificate(self):
        """
        Get the claim id of the default certificate used for claim signing, if there is one
        """

        certificate_id = self.wallet.default_certificate_claim
        if not certificate_id:
            return {'error': 'no default certificate configured'}
        return self.getclaimbyid(certificate_id)

    @staticmethod
    def prepare_claim_queries(start_position, query_size, channel_claim_infos):
        queries = [tuple()]
        names = {}
        # a table of index counts for the sorted claim ids, including ignored claims
        absolute_position_index = {}

        block_sorted_infos = sorted(channel_claim_infos.iteritems(), key=lambda x: int(x[1][1]))
        per_block_infos = {}
        for claim_id, (name, height) in block_sorted_infos:
            claims = per_block_infos.get(height, [])
            claims.append((claim_id, name))
            per_block_infos[height] = sorted(claims, key=lambda x: int(x[0], 16))

        abs_position = 0

        for height in sorted(per_block_infos.keys(), reverse=True):
            for claim_id, name in per_block_infos[height]:
                names[claim_id] = name
                absolute_position_index[claim_id] = abs_position
                if abs_position >= start_position:
                    if len(queries[-1]) >= query_size:
                        queries.append(tuple())
                    queries[-1] += (claim_id,)
                abs_position += 1
        return queries, names, absolute_position_index

    def iter_channel_claims_pages(self, queries, claim_positions, claim_names, certificate,
                                  page_size=10):
        # uwallet server returns a dict of {claim_id: (name, claim_height)}
        # first, sort the claims by block height (and by claim id int value within a block).

        # map the sorted claims into getclaimsbyids queries of query_size claim ids each

        # send the batched queries to uwallet server and iteratively validate and parse
        # the results, yield a page of results at a time.

        # these results can include those where `signature_is_valid` is False. if they are skipped,
        # page indexing becomes tricky, as the number of results isn't known until after having
        # processed them.
        # TODO: fix ^ in unetschema

        def iter_validate_channel_claims():
            for claim_ids in queries:
                batch_result = self.network.synchronous_get(
                    ("blockchain.claimtrie.getclaimsbyids", claim_ids))
                for claim_id in claim_ids:
                    claim = batch_result[claim_id]
                    if claim['name'] == claim_names[claim_id]:
                        formatted_claim = self.parse_and_validate_claim_result(claim, certificate)
                        formatted_claim['absolute_channel_position'] = claim_positions[
                            claim['claim_id']]
                        yield formatted_claim
                    else:
                        log.warning("ignoring claim with name mismatch %s %s", claim['name'],
                                    claim['claim_id'])

        yielded_page = False
        results = []
        for claim in iter_validate_channel_claims():
            results.append(claim)

            # if there is a full page of results, yield it
            if len(results) and len(results) % page_size == 0:
                yield results[-page_size:]
                yielded_page = True

        # if we didn't get a full page of results, yield what results we did get
        if not yielded_page:
            yield results

    def get_channel_claims_page(self, channel_claim_infos, certificate, page, page_size=10):
        page = page or 0
        page_size = max(page_size, 1)
        if page_size > MAX_PAGE_SIZE:
            raise Exception("page size above maximum allowed")
        start_position = (page - 1) * page_size
        queries, names, claim_positions = self.prepare_claim_queries(start_position, page_size,
                                                                     channel_claim_infos)
        page_generator = self.iter_channel_claims_pages(queries, claim_positions, names,
                                                        certificate, page_size=page_size)
        upper_bound = len(claim_positions)
        if not page:
            return None, upper_bound
        if start_position > upper_bound:
            raise IndexError("claim %i greater than max %i" % (start_position, upper_bound))
        return next(page_generator), upper_bound

    def _handle_resolve_uri_response(self, parsed_uri, block_header, raw, resolution, page=0,
                                     page_size=10):
        result = {}
        # parse an included certificate
        if 'certificate' in resolution:
            certificate_response = resolution['certificate']['result']
            certificate_resolution_type = resolution['certificate']['resolution_type']
            if certificate_resolution_type == "winning" and certificate_response:
                if 'height' in certificate_response:
                    height = certificate_response['height']
                    depth = self.network.get_server_height() - height
                    certificate_result = Commands._verify_proof(parsed_uri.name,
                                                                block_header['claim_trie_root'],
                                                                certificate_response,
                                                                height, depth)
                    result['certificate'] = self.parse_and_validate_claim_result(certificate_result,
                                                                                 raw=raw)
            elif certificate_resolution_type == "claim_id":
                result['certificate'] = self.parse_and_validate_claim_result(certificate_response,
                                                                             raw=raw)
            elif certificate_resolution_type == "sequence":
                result['certificate'] = self.parse_and_validate_claim_result(certificate_response,
                                                                             raw=raw)
            else:
                log.error("unknown response type: %s", certificate_resolution_type)

            if 'certificate' in result:
                certificate = result['certificate']
                if 'unverified_claims_in_channel' in resolution:
                    max_results = len(resolution['unverified_claims_in_channel'])
                    result['claims_in_channel'] = max_results
                else:
                    result['claims_in_channel'] = 0
            else:
                result['error'] = "claim not found"
                result['success'] = False
                result['uri'] = str(parsed_uri)

        else:
            certificate = None

        # if this was a resolution for a name, parse the result
        if 'claim' in resolution:
            claim_response = resolution['claim']['result']
            claim_resolution_type = resolution['claim']['resolution_type']
            if claim_resolution_type == "winning" and claim_response:
                if 'height' in claim_response:
                    height = claim_response['height']
                    depth = self.network.get_server_height() - height
                    claim_result = Commands._verify_proof(parsed_uri.name,
                                                          block_header['claim_trie_root'],
                                                          claim_response,
                                                          height, depth)
                    result['claim'] = self.parse_and_validate_claim_result(claim_result,
                                                                           certificate,
                                                                           raw)
            elif claim_resolution_type == "claim_id":
                result['claim'] = self.parse_and_validate_claim_result(claim_response,
                                                                       certificate,
                                                                       raw)
            elif claim_resolution_type == "sequence":
                result['claim'] = self.parse_and_validate_claim_result(claim_response,
                                                                       certificate,
                                                                       raw)
            else:
                log.error("unknown response type: %s", claim_resolution_type)

        # if this was a resolution for a name in a channel make sure there is only one valid
        # match
        elif 'unverified_claims_for_name' in resolution and 'certificate' in result:
            unverified_claims_for_name = resolution['unverified_claims_for_name']

            channel_info = self.get_channel_claims_page(unverified_claims_for_name,
                                                        result['certificate'], page=1)
            claims_in_channel, upper_bound = channel_info

            if len(claims_in_channel) > 1:
                log.error("Multiple signed claims for the same name")
            elif not claims_in_channel:
                log.error("No valid claims for this name for this channel")
            else:
                result['claim'] = claims_in_channel[0]

        # parse and validate claims in a channel iteratively into pages of results
        elif 'unverified_claims_in_channel' in resolution and 'certificate' in result:
            ids_to_check = resolution['unverified_claims_in_channel']
            channel_info = self.get_channel_claims_page(ids_to_check, result['certificate'],
                                                        page=page, page_size=page_size)
            claims_in_channel, upper_bound = channel_info

            if claims_in_channel:
                result['claims_in_channel'] = claims_in_channel
        elif 'error' not in result:
            result['error'] = "claim not found"
            result['success'] = False
            result['uri'] = str(parsed_uri)

        return result

    @command('n')
    def getvalueforuri(self, uri, raw=False, page=0, page_size=10):
        """
        Resolve a ULD URI
        """

        result = self.getvaluesforuris(raw, page, page_size, uri)
        if uri in result:
            return result[uri]
        return result

    @command('n')
    def getvaluesforuris(self, raw=False, page=0, page_size=10, *uris):
        """
        Resolve a ULD URI
        """

        page = int(page)
        page_size = int(page_size)
        uris_to_send = ()

        for uri in uris:
            try:
                parse_unet_uri(uri)
                uris_to_send += (str(uri),)
            except URIParseError as err:
                return {'error': err.message}

        height = self.network.get_local_height() - RECOMMENDED_CLAIMTRIE_HASH_CONFIRMS + 1
        block_header = self.network.blockchain.read_header(height)
        block_hash = self.network.blockchain.hash_header(block_header)
        response = self.network.synchronous_get(('blockchain.claimtrie.getvaluesforuris',
                                                 (block_hash,) + uris_to_send))
        result = {}
        for uri in response:
            result[uri] = self._handle_resolve_uri_response(parse_unet_uri(str(uri)), block_header,
                                                            raw, response[uri], page=page,
                                                            page_size=page_size)
        return result

    @command('n')
    def getsignaturebyid(self, claim_id):
        """
        Get signature information for a claim by its claim id
        """

        response = {'has_signature': False}
        raw_claim = self.getclaimbyid(claim_id, raw=True)

        if raw_claim:
            try:
                decoded_claim = smart_decode(raw_claim['value'].decode('hex'))
                response['decoded_claim'] = True
            except DecodeError:
                response['decoded_claim'] = False
                response['error'] = "Could not decode claim value"
            if response['decoded_claim'] and decoded_claim.has_signature:
                response['has_signature'] = True
                response['signature'] = decoded_claim.signature
                response['certificate'] = self.getclaimbyid(decoded_claim.certificate_id)
                validated, channel_name = self.validate_claim_signature_and_get_channel_name(
                    decoded_claim, response['certificate'], raw_claim['address'])
                response['channel_name'] = channel_name
                if validated:
                    response['signature_is_valid'] = True
                else:
                    response['signature_is_valid'] = False
            else:
                response['has_signature'] = False
        else:
            response['error'] = "claim does not exist"
        return response

    @command('n')
    def getclaimsfromtx(self, txid, raw=False):
        """
        Return the claims which are in a transaction
        """

        result = self.network.synchronous_get(('blockchain.claimtrie.getclaimsintx', [txid]))
        return self.parse_and_validate_claim_result(result, raw=raw)

    @command('n')
    def getclaimbyoutpoint(self, txid, nout, raw=False):
        """
        Return claim at outpoint (txid:nout)
        If no claim exists at outpoint, or outpoint not found, return
        dictionary where 'success' is False and 'error' is 'claim not found'
        """

        claims = self.network.synchronous_get(('blockchain.claimtrie.getclaimsintx', [txid]))
        claim_not_found_out = {'success': False, 'error': 'claim not found',
                               'outpoint': '%s:%i' % (txid, nout)}
        if claims is None:
            return claim_not_found_out
        for claim in claims:
            if claim['nout'] == nout:
                return self.parse_and_validate_claim_result(claim, raw=raw)
        return claim_not_found_out

    @command('n')
    def getclaimsforname(self, name, raw=False):
        """
        Return all claims and supports for a name
        """

        result = self.network.synchronous_get(('blockchain.claimtrie.getclaimsforname', [name]))
        claims_for_return = []
        for claim in result['claims']:
            claims_for_return.append(self.parse_and_validate_claim_result(claim, raw=raw))
        result['claims'] = claims_for_return
        return result

    @command('n')
    def getclaimssignedby(self, claim_id, raw=False):
        """
        Request claims signed by a given certificate
        """

        result = self.network.synchronous_get(('blockchain.claimtrie.getclaimssignedbyid',
                                               [claim_id]))
        return [self.parse_and_validate_claim_result(claim, raw=raw) for claim in result]

    @command('n')
    def getclaimsinchannel(self, uri, raw=False):
        """
        Get claims in a channel for a uri
        """

        parsed = parse_unet_uri(uri)
        if not parsed.is_channel:
            return {'error': 'not a channel uri'}
        elif parsed.claim_sequence is not None:
            claims = self.network.synchronous_get(
                ('blockchain.claimtrie.getclaimssignedbynthtoname',
                 [parsed.name, parsed.claim_sequence]))
        elif parsed.claim_id is not None:
            claims = self.network.synchronous_get(('blockchain.claimtrie.getclaimssignedbyid',
                                                   [parsed.claim_id]))
        else:
            claims = self.network.synchronous_get(('blockchain.claimtrie.getclaimssignedby',
                                                   [parsed.name]))
        if claims:
            return [self.parse_and_validate_claim_result(claim, raw=raw) for claim in claims]
        return []

    @command('n')
    def getblock(self, blockhash):
        """
        Return a block matching the given blockhash
        """

        return self.network.synchronous_get(('blockchain.block.get_block', [blockhash]))

    @command('n')
    def getbestblockhash(self):
        height = self.network.get_local_height()
        if height < 0:
            return None
        header = self.network.blockchain.read_header(height)
        return self.network.blockchain.hash_header(header)

    @command('n')
    def getmostrecentblocktime(self):
        height = self.network.get_local_height()
        if height < 0:
            return None
        header = self.network.get_header(self.network.get_local_height())
        return header['timestamp']

    @command('n')
    def getnetworkstatus(self):
        out = {'is_connecting': self.network.is_connecting(),
               'is_connected': self.network.is_connected(),
               'local_height': self.network.get_local_height(),
               'server_height': self.network.get_server_height(),
               'blocks_behind': self.network.get_blocks_behind(),
               'retrieving_headers': self.network.blockchain.retrieving_headers}
        return out

    @command('n')
    def getclaimtrie(self):
        """
        Return the entire claim trie
        """

        return self.network.synchronous_get(('blockchain.claimtrie.get', []))

    @command('n')
    def getclaimbyid(self, claim_id, raw=False):
        """
        Get claim by claim id
        """

        result = self.network.synchronous_get(('blockchain.claimtrie.getclaimbyid', [claim_id]))
        return self.parse_and_validate_claim_result(result, raw=raw)

    @command('n')
    def getclaimsbyids(self, claim_ids, raw=False):
        """
        Get a dictionary of claim results keyed by claim id for a list of claim ids
        """

        def iter_certificate_ids(claim_results):
            for claim_id, claim_result in claim_results.iteritems():
                if claim_result and 'value' in claim_result:
                    try:
                        decoded = smart_decode(claim_result['value'])
                        if decoded.has_signature:
                            yield claim_id, decoded.certificate_id
                    except DecodeError:
                        pass

        def iter_certificate_claims(certificate_results):
            for claim_id, claim_result in certificate_results.iteritems():
                yield claim_id, self.offline_parse_and_validate_claim_result(claim_result, None,
                                                                             raw)

        def iter_resolve_and_parse(to_query):
            claim_results = self.network.synchronous_get(("blockchain.claimtrie.getclaimsbyids",
                                                          to_query))
            certificate_infos = dict(iter_certificate_ids(claim_results))

            cert_results = self.network.synchronous_get(("blockchain.claimtrie.getclaimsbyids",
                                                         certificate_infos.values()))
            certificates = dict(iter_certificate_claims(cert_results))

            for claim_id, claim_result in claim_results.iteritems():
                if claim_id in certificate_infos:
                    certificate_id = certificate_infos[claim_id]
                    certificate = certificates[certificate_id]
                else:
                    certificate = None
                yield claim_id, self.offline_parse_and_validate_claim_result(claim_result,
                                                                             certificate, raw)

        def iter_queries(remaining):
            while remaining:
                query = remaining[:MAX_BATCH_QUERY_SIZE]
                remaining = remaining[MAX_BATCH_QUERY_SIZE:]
                for claim_id, claim in iter_resolve_and_parse(query):
                    yield claim_id, claim

        return dict(iter_queries(claim_ids))

    @command('n')
    def getnthclaimforname(self, name, n, raw=False):
        """
        Get the last update to the nth claim to a name
        """

        result = self.network.synchronous_get(('blockchain.claimtrie.getnthclaimforname',
                                               [name, n]))
        return self.parse_and_validate_claim_result(result, raw=raw)

    @command('wn')
    def getnameclaims(self, raw=False, include_abandoned=False, include_supports=True,
                      txid=None, nout=None, claim_id=None, skip_validate_signatures=False):
        """
        Get my name claims from wallet
        """

        # get the name claims from the wallet
        result = self.wallet.get_name_claims(include_abandoned=include_abandoned,
                                             include_supports=include_supports)
        name_claims = []

        # set of claim ids of claims in the wallet
        claim_ids = {c['claim_id'] for c in result}

        # dictionary of claims (not including supports) in the wallet, keyed by claim id
        claims = {}

        # dictionary of decoded ClaimDict objects, keyed by claim id
        claim_dict_objs = {}

        # list of (<claim_id>, <certificate_id>) tuples, where <certificate_id> is None if
        # the claim is not signed
        # note: the certificate claim is not necessarily in the wallet
        claim_tuples = []

        # list of certificate claim ids not known by the wallet but used for signing
        needed_certificates = []

        # list of support transactions
        supports = []

        for claim in result:
            # if we're looking for a specific claim by its id, skip all other claims
            if claim_id and claim_id != claim['claim_id']:
                continue
            # if we're looking for a specific claim by its outpoint, skip all other claims
            if txid is not None:
                if claim['txid'] != txid:
                    continue
            if nout is not None:
                if claim['nout'] != nout:
                    continue
            # if transaction is a claim or update (supports don't have a `value`)
            if 'value' in claim:
                try:
                    decoded = smart_decode(claim['value'])
                    if not isinstance(decoded, ClaimDict):
                        log.warning("Failed to decode %s to a claim dict, instead got %s",
                                    claim['name'], str(type(decoded)))
                    if not skip_validate_signatures:
                        certificate_id = decoded.certificate_id
                        # if the claim is signed but the certificate id is not for a claim in the
                        # wallet, add it to the list of needed claims
                        if certificate_id and certificate_id not in claim_ids:
                            needed_certificates.append(certificate_id)
                    else:
                        certificate_id = None
                    claim_tuples.append((claim['claim_id'], certificate_id))
                    claim['value'] = decoded
                    claims[claim['claim_id']] = claim
                except DecodeError:
                    claim_tuples.append((claim['claim_id'], None))
                    claims[claim['claim_id']] = claim
            else:
                supports.append(claim)

        # if we're not skipping signature validation, claim_tuples now maps all the claims in the
        # wallet to their certificate claims (if applicable) and any certificate claims not also in
        # the wallet are in the needed_certificates list
        if needed_certificates:
            log.warning("Fetching %i certificate claims for claims made with certificates not in "
                        "this wallet", len(needed_certificates))
            needed_cert_results = self.getclaimsbyids(needed_certificates)
            # put the fetched certificate claims into the claims dictionary for use validating
            # the signatures of the claims in the wallet
            for _claim_id in needed_cert_results:
                claims[_claim_id] = needed_cert_results[_claim_id]
                claims[_claim_id]['value'] = smart_decode(needed_cert_results[_claim_id]['value'])

        # use pre-decoded ClaimDicts rather than decoding them each time we call
        # offline_parse_and_validate_claim_result
        for _claim_id in claims:
            claim_value = claims[_claim_id]['value']
            claim_dict_objs[_claim_id] = claim_value
        # format (and validate, unless skip_validate_signatures) the resulting claims for return
        for _claim_id, certificate_id in claim_tuples:
            if certificate_id and certificate_id in claims:
                certificate = claims[certificate_id]
                certificate_obj = claim_dict_objs[certificate_id]
            else:
                certificate = None
                certificate_obj = None

            claim = claims[_claim_id]
            claim_obj = claim_dict_objs[_claim_id]
            if isinstance(claim_obj, ClaimDict):
                decoded_claim = claim_obj
            else:
                decoded_claim = None

            parsed = self.offline_parse_and_validate_claim_result(
                claim, certificate=certificate, raw=raw, decoded_claim=decoded_claim,
                decoded_certificate=certificate_obj,
                skip_validate_signatures=skip_validate_signatures)
            name_claims.append(parsed)

        # format and add supports to claims for return
        for support in supports:
            parsed = format_amount_value(support)
            name_claims.append(parsed)
        return name_claims

    @command('wp')
    def getcertificateclaims(self, raw=False, include_abandoned=False):
        """
        Get my claims containing certificates
        """

        certificate_claims = []
        name_claims = self.wallet.get_name_claims(include_abandoned=include_abandoned,
                                                  include_supports=False)
        for claim in name_claims:
            try:
                decoded = smart_decode(claim['value'])
                if decoded.is_certificate:
                    cert_result = self.offline_parse_and_validate_claim_result(
                        claim, None, raw=raw, decoded_claim=decoded, skip_validate_signatures=True)
                    if self.cansignwithcertificate(cert_result['claim_id']):
                        cert_result['can_sign'] = True
                    else:
                        cert_result['can_sign'] = False
                    certificate_claims.append(cert_result)
            except DecodeError:
                pass
        return certificate_claims

    @command('wpn')
    def getcertificatesforsigning(self, raw=False):
        """
        Get certificate claims that are usable for signing, the claims are not necessarily in the
        wallet
        """

        my_certs = self.getcertificateclaims(raw=raw)
        certificate_claim_ids = self.wallet.get_certificate_claim_ids_for_signing()
        result = []
        for cert_claim in my_certs:
            cert_claim['is_mine'] = True
            result.append(cert_claim)
            certificate_claim_ids.remove(cert_claim['claim_id'])
        if certificate_claim_ids:
            imported_certs = self.getclaimsbyids(certificate_claim_ids, raw=raw)
            for claim_id, cert_claim in imported_certs.iteritems():
                cert_claim['is_mine'] = False
                result.append(cert_claim)
        return result

    def _calculate_fee(self, inputs, outputs, set_tx_fee):
        if set_tx_fee is not None:
            return set_tx_fee
        dummy_tx = Transaction.from_io(inputs, outputs)
        # fee per kb will default to RECOMMENDED_FEE, which is 50000
        # relay fee will default to 5000
        # fee is max(relay_fee, size is fee_per_kb * esimated_size)
        # will be roughly 10,000 deweys (0.0001 UT), standard abandon should be about 200 bytes
        # this is assuming config is not set to dynamic, which in case it will get fees from
        # ulords fee estimation algorithm

        size = dummy_tx.estimated_size()
        fee = Transaction.fee_for_size(self.wallet.relayfee(), self.wallet.fee_per_kb(self.config),
                                       size)
        return fee

    @command('w')
    def verify_claim_schema(self, val):
        """
        Parse an encoded claim value
        """

        try:
            # claim_value_decoded = base64.b64decode(val.decode('hex'))
            # decoded = smart_decode(claim_value_decoded)
            decoded = smart_decode(val)
            results = {'claim_dictionary': decoded.claim_dict,
                       'serialized': decoded.serialized.encode('hex')}
            return results
        except DecodeError as err:
            return {'error': err}

    @command('wpn')
    def claim(self, name, val, amount=1, certificate_id=None, broadcast=True, claim_addr=None,
              tx_fee=None, change_addr=None, raw=False, skip_validate_schema=None,
              skip_update_check=None):
        """
        Claim a name
        """

        if skip_validate_schema and certificate_id:
            return {'success': False, 'reason': 'refusing to sign claim without validated schema'}

        parsed_claim = self.verify_request_to_make_claim(name, val, certificate_id)
        if 'error' in parsed_claim:
            return {'success': False, 'reason': parsed_claim['error']}

        parsed_uri = parse_unet_uri(name)
        name = parsed_claim['name']
        val = parsed_claim['val']
        certificate_id = parsed_claim['certificate_id']

        if not skip_update_check:
            my_claims = [claim
                         for claim in self.getnameclaims(include_supports=False,
                                                         skip_validate_signatures=True)
                         if claim['name'] == name]
            if len(my_claims) > 1:
                return {'success': False, 'reason': "Dont know which claim to update"}
            if my_claims:
                my_claim = my_claims[0]

                if parsed_uri.claim_id and not my_claim['claim_id'].startswith(parsed_uri.claim_id):
                    return {'success': False,
                            'reason': 'claim id in URI does not match claim to update'}
                log.info("There is an unspent claim in your wallet for this name, updating "
                         "it instead")
                return self.update(name, val, amount=amount, broadcast=broadcast,
                                   claim_addr=claim_addr,
                                   tx_fee=tx_fee, change_addr=change_addr,
                                   certificate_id=certificate_id, raw=raw,
                                   skip_validate_schema=skip_validate_schema)

        # decode claim value as hex
        if not raw:
            val = val.decode('hex')

        # validate claim and change address if either where given, get least used if not provided
        if claim_addr is None:
            claim_addr = self.wallet.get_least_used_address()
        if not base_decode(claim_addr, ADDRESS_LENGTH, 58):
            return {'error': 'invalid claim address'}

        if change_addr is None:
            change_addr = self.wallet.get_least_used_address(for_change=True)
        if not base_decode(change_addr, ADDRESS_LENGTH, 58):
            return {'error': 'invalid change address'}

        amount = int(COIN * amount)
        if amount <= 0:
            return {'success': False, 'reason': 'Amount must be greater than 0'}
        if tx_fee is not None:
            tx_fee = int(COIN * tx_fee)
            if tx_fee < 0:
                return {'success': False, 'reason': 'tx_fee must be greater than or equal to 0'}

        claim_value = None

        if not skip_validate_schema:
            try:
                claim_value = smart_decode(val)
            except DecodeError as err:
                return {'success': False,
                        'reason': 'Decode error: %s' % err}

            if not parsed_uri.is_channel and claim_value.is_certificate:
                return {'success': False,
                        'reason': 'Certificates must have URIs beginning with /"@/"'}

            if claim_value.has_signature:
                return {'success': False, 'reason': 'Claim value is already signed'}

            if certificate_id is not None:
                if not self.cansignwithcertificate(certificate_id):
                    return {'success': False,
                            'reason': 'Cannot sign for certificate %s' % certificate_id}

        if certificate_id and claim_value:
            signing_key = self.wallet.get_certificate_signing_key(certificate_id)
            signed = claim_value.sign(signing_key, claim_addr, certificate_id, curve=SECP256k1)
            val = signed.serialized

        # commission : The amount paid to the platform.  --JustinQP
        commission = amount - BINDING_FEE
        outputs = [(TYPE_ADDRESS | TYPE_CLAIM, ((name, val), claim_addr), BINDING_FEE),
                   (TYPE_ADDRESS, PLATFORM_ADDRESS, commission)]
        coins = self.wallet.get_spendable_coins()
        try:
            tx = self.wallet.make_unsigned_transaction(coins, outputs,
                                                       self.config, tx_fee, change_addr)
        except NotEnoughFunds:
            return {'success': False,
                    'reason': 'Not enough funds'}
        self.wallet.sign_transaction(tx, self._password)
        if broadcast:
            success, out = self.wallet.send_tx(tx)
            if not success:
                return {'success': False, 'reason': out}

        nout = None
        for i, output in enumerate(tx._outputs):
            if output[0] & TYPE_CLAIM:
                nout = i
        assert nout is not None

        claimid = encode_claim_id_hex(claim_id_hash(rev_hex(tx.hash()).decode('hex'), nout))
        return {
			"success": True, 
			"txid": tx.hash(), 
			"nout": nout, 
			"tx": str(tx),
            "fee": str(Decimal(tx.get_fee()) / COIN), 
			"claim_id": claimid
			}

    @command('wpn')
    def claimcertificate(self, name, amount, broadcast=True, claim_addr=None, tx_fee=None,
                         change_addr=None, set_default_certificate=None):
        """
        Generate a new signing key and make a certificate claim
        """

        if not parse_unet_uri(name).is_channel:
            return {'error': 'non compliant uri for certificate'}

        secp256k1_private_key = get_signer(SECP256k1).generate().private_key.to_pem()
        claim = ClaimDict.generate_certificate(secp256k1_private_key, curve=SECP256k1)
        encoded_claim = claim.serialized.encode('hex')
        result = self.claim(name, encoded_claim, amount, broadcast=broadcast,
                            claim_addr=claim_addr, tx_fee=tx_fee, change_addr=change_addr)

        if result['success']:
            self.wallet.save_certificate(result['claim_id'], secp256k1_private_key)
            self.wallet.set_default_certificate(result['claim_id'],
                                                overwrite_existing=set_default_certificate)
        return result

    @staticmethod
    def _deserialize_certificate_key(serialized_certificate_info):
        """
        :param serialized_certificate_info:
        :return: certificate claim id hex, pem encoded private key
        """

        cert_info = serialized_certificate_info[:40]
        priv_key_info = serialized_certificate_info[40:]
        return cert_info, priv_key_info.decode('hex')

    @staticmethod
    def _serialize_certificate_key(certificate_id, pem_private_key):
        info_str = certificate_id + pem_private_key.encode('hex')
        return info_str

    @command('wp')
    def exportcertificateinfo(self, certificate_id):
        """
        Export serialized channel signing information
        """

        if not self.cansignwithcertificate(certificate_id):
            return {'error': 'certificate private is not in the wallet: %s' % certificate_id}
        priv_key = self.wallet.get_certificate_signing_key(certificate_id)
        if not priv_key:
            return {'error': 'failed to key signing key for %s' % certificate_id}
        return self._serialize_certificate_key(certificate_id, priv_key)

    def _import_certificate_info(self, certificate_id, signing_key, certificate_claim):
        if self.cansignwithcertificate(certificate_id):
            return {'error': 'refusing to overwrite certificate key already in the wallet',
                    'success': False}
        certificate_claim_obj = ClaimDict.load_dict(certificate_claim['value'])
        if not certificate_claim_obj.is_certificate:
            return {'error': 'claim is not a certificate', 'success': False}
        if not certificate_claim_obj.validate_private_key(signing_key, certificate_id):
            return {'error': 'private key does not match certificate', 'success': False}
        self.wallet.save_certificate(certificate_id, signing_key)
        return {'success': True}

    @command('wpn')
    def importcertificateinfo(self, *serialized_certificate_info):
        """
        Import serialized channel infos
        """

        infos = {}
        response = {}
        for info in serialized_certificate_info:
            certificate_id, signing_key = self._deserialize_certificate_key(info)
            infos[certificate_id] = signing_key
        certificate_claims = self.getclaimsbyids(infos.keys())
        for cert_id, cert_claim in certificate_claims.iteritems():
            response[cert_id] = self._import_certificate_info(cert_id, infos[cert_id], cert_claim)
        return response

    @command('wpn')
    def updateclaimsignature(self, name, amount=None, claim_id=None, certificate_id=None):
        """
        Update an unsigned claim with a signature
        """

        claim_value = None
        claim_address = None
        if claim_id is None:
            claims = self.getnameclaims(raw=True, include_supports=False,
                                        skip_validate_signatures=True)
            for claim in claims:
                if claim['name'] == name and not claim['is_spent']:
                    claim_id = claim['claim_id']
                    claim_value = claim['value']
                    claim_address = claim['address']
                    break

        if claim_id is None or claim_value is None:
            return {'error': 'no claim to update'}
        claim = smart_decode(claim_value)
        if certificate_id is None:
            certificate_id = claim.certificate_id
            certificate = self.getclaimbyid(certificate_id)
            if not certificate:
                raise Exception('Certificate claim {} not found'.format(claim.certificate_id))
        elif not self.cansignwithcertificate(certificate_id):
            return {
                'error': ('can update claim for unet://{}#{}, but the signing key is '
                          'missing for certificate {}').format(name, claim_id, certificate_id)
            }
        else:
            certificate = self.getclaimbyid(str(certificate_id))
            if not certificate:
                raise Exception('Certificate claim {} not found'.format(claim.certificate_id))
        validated, channel_name = self.validate_claim_signature_and_get_channel_name(claim,
                                                                                     certificate,
                                                                                     claim_address)
        if validated:
            return {
                'error': 'unet://{}#{} has a valid signature already'.format(name, claim_id)
            }

        return self.update(name, claim.serialized_no_signature, amount=amount,
                           certificate_id=certificate_id, claim_id=claim_id, raw=True)

    @command('wpn')
    def updatecertificate(self, name, amount=None, revoke=False, val=None):
        """
        Update a certificate claim
        """

        if not parse_unet_uri(name).is_channel:
            return {'error': 'non compliant uri for certificate'}
        elif not revoke and not val:
            return {'error': 'nothing to update with'}

        if revoke:
            secp256k1_private_key = get_signer(SECP256k1).generate().private_key.to_pem()
            certificate = ClaimDict.generate_certificate(secp256k1_private_key, curve=SECP256k1)
            result = self.update(name, certificate.serialized, amount=amount, raw=True)
            self.wallet.save_certificate(result['claim_id'], secp256k1_private_key)
        else:
            decoded = smart_decode(val)
            if not decoded.is_certificate:
                return {'error': 'value is not a certificate'}
            result = self.update(name, decoded.serialized, amount=amount, raw=True)
        return result

    @command('wp')
    def cansignwithcertificate(self, certificate_id):
        """
        Can sign with given claim certificate
        """

        if self.wallet.get_certificate_signing_key(certificate_id) is not None:
            return True
        return False

    @command('wpn')
    def support(self, name, claim_id, amount, broadcast=True, claim_addr=None, tx_fee=None,
                change_addr=None):
        """
        Support a name claim
        """

        if claim_addr is None:
            claim_addr = self.wallet.get_least_used_address()
        if change_addr is None:
            change_addr = self.wallet.get_least_used_address(for_change=True)

        claim_id = decode_claim_id_hex(claim_id)
        amount = int(COIN * amount)
        if amount <= 0:
            return {'success': False, 'reason': 'Amount must be greater than 0'}
        if tx_fee is not None:
            tx_fee = int(COIN * tx_fee)
            if tx_fee < 0:
                return {'success': False, 'reason': 'tx_fee must be greater than or equal to 0'}

        outputs = [(TYPE_ADDRESS | TYPE_SUPPORT, ((name, claim_id), claim_addr), amount)]
        coins = self.wallet.get_spendable_coins()
        try:
            tx = self.wallet.make_unsigned_transaction(coins, outputs, self.config, tx_fee,
                                                       change_addr)
        except NotEnoughFunds:
            return {'success': False, 'reason': 'Not enough funds'}
        self.wallet.sign_transaction(tx, self._password)
        if broadcast:
            success, out = self.wallet.send_tx(tx)
            if not success:
                return {'success': False, 'reason': out}

        nout = None
        for i, output in enumerate(tx._outputs):
            if output[0] & TYPE_SUPPORT:
                nout = i

        return {"success": True, "txid": tx.hash(), "nout": nout, "tx": str(tx),
                "fee": str(Decimal(tx.get_fee()) / COIN)}

    @command('wpn')
    def sendwithsupport(self, claim_id, amount, broadcast=True, tx_fee=None,
                        change_addr=None):
        """
        Send credits to a claim's address via a support transaction
        """

        claim = self.getclaimbyid(claim_id)
        if claim.get('signature_is_valid') is False:
            return {'error: refusing to support a claim with an invalid signature'}
        claim_addr = claim['address']
        name = claim['name']
        return self.support(name, claim_id, amount, broadcast, claim_addr, tx_fee, change_addr)

    def verify_request_to_make_claim(self, uri, val, certificate_id):
        try:
            parsed_uri = parse_unet_uri(uri)
        except URIParseError as err:
            return {'error': 'Failed to decode URI: %s' % err}

        # val = base64.b64decode(val.decode('hex'))
        if parsed_uri.is_channel:
            if parsed_uri.path:
                try:
                    if smart_decode(val).is_certificate:
                        return {'error': 'Claim in a channel should not contain a certificate'}
                except DecodeError as err:
                    return {'error': 'Failed to decode claim: %s' % err}
                name = parsed_uri.path
            else:
                try:
                    if not smart_decode(val).is_certificate:
                        return {'error': 'Channel claim does not contain a certificate'}
                except DecodeError as err:
                    return {'error': 'Failed to decode certificate in claim: %s' % err}
                name = parsed_uri.name
        else:
            name = parsed_uri.name

        return {'name': name, 'certificate_id': certificate_id, 'val': val}

    @command('wpn')
    def renewclaimsbeforeexpiration(self, height, broadcast=True, skip_validate_schema=False):
        """
        Renew unexpired claims that will expire by the specified height.
        Unexpired claims will be updated to an identical claim, and supports
        will be spent into an identical support

        :param height: (int) update claims expiring before or at this block height
        :param skip_validate_schema: (bool) skip validation of schema
        :param broadcast: (bool) broadcast transactions
        :returns dictionary, {<outpoint string>: formatted claim result}
        """
        claims = self.wallet.get_name_claims(include_abandoned=False, include_supports=True,
                                             exclude_expired=True)
        pending_expiration = [claim for claim in claims if claim['expiration_height'] <= height]
        results = {}
        for claim in pending_expiration:
            outpoint = "%s:%i" % (claim['txid'], claim['nout'])
            results[outpoint] = self._renewclaim(claim, broadcast, skip_validate_schema)
        return results

    @command('wpn')
    def renewclaim(self, txid, nout, broadcast=True, skip_validate_schema=False):
        """
        Renew claim. Unexpired claims will be udpated to an identical claim
        and supports will be spent into an identical support.

        :param txid: (str) txid of claim
        :param nout: (int) nout of claim
        :param skip_validate_schema: (bool) skip validation of schema
        :param broadcast: (bool) True if broadcasting the claim
        :returns dictionary: formatted claim result
        """
        claims = self.wallet.get_name_claims(include_abandoned=False, include_supports=True,
                                             exclude_expired=True)
        claims = [claim for claim in claims if claim['txid'] == txid and claim['nout'] == nout]
        if not claims:
            return {'success': False, 'reason': 'no matching claim found for %s:%i' % (txid, nout)}
        claim = claims[0]
        return self._renewclaim(claim, broadcast, skip_validate_schema)

    def _renewclaim(self, claim, broadcast=True, skip_validate_schema=False):
        log.info("Updating unet://%s#%s (%s)", claim['name'], claim['claim_id'],
                 claim['category'])
        if claim['category'] != 'support':
            out = self.update(claim['name'], claim['value'], claim_id=claim['claim_id'],
                              txid=claim['txid'], nout=claim['nout'],
                              skip_validate_schema=skip_validate_schema, broadcast=broadcast)
        else:
            out = self.updatesupport(claim['txid'], claim['nout'], broadcast=broadcast)
        return out

    @command('wpn')
    def updatesupport(self, txid, nout, amount=None, broadcast=True,
                      claim_addr=None, tx_fee=None, change_addr=None):
        """
        Update a claim support, will spend support into a new support

        :param txid: (str) txid of support transaction to update
        :param nout: (int) nout of support transaction to update
        :param amount: (float) amount to support claim by, defaults to the current amount
        :param broadcast: (bool) broadcast the transaction
        :param claim_addr: (str) address to send support to
        :param tx_fee: (float) tx fee
        :param change_addr: (str) address to send change to
        :returns formatted claim result
        """

        if claim_addr is None:
            claim_addr = self.wallet.get_least_used_address()
        if change_addr is None:
            change_addr = self.wallet.get_least_used_address(for_change=True)

        supports = self.wallet.get_name_claims(include_supports=True)
        claim_support = [support for support in supports if
                         support['txid'] == txid and support['nout'] == nout and
                         support['category'] == 'support']
        if not claim_support:
            return {'success': False, 'reason': 'Support not found for txo %s:%i' % (txid,
                                                                                     nout)}
        claim_support = claim_support[0]
        claim_id = claim_support['claim_id']
        name = claim_support['name']
        val = None

        out = self._get_input_output_for_updates(name, val, amount, claim_id, txid, nout,
                                                 claim_addr, change_addr, tx_fee,
                                                 is_support_replace=True)
        if not out['success']:
            return out
        else:
            inputs = out['inputs']
            outputs = out['outputs']

        tx = Transaction.from_io(inputs, outputs)
        self.wallet.sign_transaction(tx, self._password)
        if broadcast:
            success, out = self.wallet.send_tx(tx)
            if not success:
                return {"success": False, "reason": out}
        nout = None
        amount = 0
        for i, output in enumerate(tx._outputs):
            if output[0] & TYPE_SUPPORT:
                nout = i
                amount = output[2]
        return {
            "success": True,
            "txid": tx.hash(),
            "nout": nout,
            "tx": str(tx),
            "fee": str(Decimal(tx.get_fee()) / COIN),
            "amount": str(Decimal(amount) / COIN),
            "claim_id": claim_id
        }

    @command('wpn')
    def update(self, name, val, amount=None, certificate_id=None, claim_id=None, txid=None,
               nout=None, broadcast=True, claim_addr=None, tx_fee=None, change_addr=None, raw=None,
               skip_validate_schema=None):
        """
        Update a name claim

        :param name: (str) name of claim being updated
        :param val: (str) calim value to update to
        :param amount: (float) amount to update, defaults to the amount in the
            claim being updated minus tx fees
        :param certificate_id: claim ID of the certificate associated with the claim
        :param claim_id: claim ID of the claim being updated
        :param txid: (str) txid of support transaction to update
        :param nout: (int) nout of support transaction to update
        :param broadcast: (bool) broadcast the transaction
        :param claim_addr: (str) address to send support to
        :param tx_fee: (float) tx fee
        :param change_addr: (str) address to send change to
        :param raw: (bool) default False. If True, val is byte encoded already
            so do not decode from hex string
        :param skip_validate_schema:default False. If True, skip validation of
            claim schema in val, and skip claim signing. Cannot be True if
            certificate_id is not None

        :returns formatted claim result
        """
        #gl.flag_claim = True
        if skip_validate_schema and certificate_id:
            return {'success': False, 'reason': 'refusing to sign claim without validated schema'}

        parsed_claim = self.verify_request_to_make_claim(name, val, certificate_id)
        if 'error' in parsed_claim:
            return {'success': False, 'reason': parsed_claim['error']}

        parsed_uri = parse_unet_uri(name)
        name = parsed_claim['name']
        val = parsed_claim['val']
        certificate_id = parsed_claim['certificate_id']

        if not raw:
            val = val.decode('hex')
        if not skip_validate_schema:
            try:
                decoded_claim = smart_decode(val)
            except DecodeError as err:
                return {'success': False, 'reason': 'Decode error: %s' % err}
        else:
            decoded_claim = None
        if claim_addr is None:
            claim_addr = self.wallet.get_least_used_address()
        if not base_decode(claim_addr, ADDRESS_LENGTH, 58):
            return {'error': 'invalid claim address'}

        if change_addr is None:
            change_addr = self.wallet.get_least_used_address(for_change=True)
        if not base_decode(change_addr, ADDRESS_LENGTH, 58):
            return {'error': 'invalid change address'}
        if claim_id is None or txid is None or nout is None:
            claims = self.getnameclaims(skip_validate_signatures=True)
            for claim in claims:
                if claim['name'] == name and not claim['is_spent']:
                    claim_id = claim['claim_id']
                    txid = claim['txid']
                    nout = claim['nout']
                    break
            if not claim_id:
                return {'success': False, 'reason': 'No claim to update'}

        if not skip_validate_schema:
            try:
                claim_value = smart_decode(val)
            except DecodeError as err:
                return {'success': False,
                        'reason': 'Decode error: %s' % err}

            if not parsed_uri.is_channel and claim_value.is_certificate:
                return {'success': False,
                        'reason': 'Certificates must have URIs beginning with /"@/"'}

            if claim_value.has_signature:
                return {'success': False, 'reason': 'Claim value is already signed'}

            if certificate_id is not None:
                if not self.cansignwithcertificate(certificate_id):
                    return {'success': False,
                            'reason': 'Cannot sign for certificate %s' % certificate_id}

            if certificate_id and claim_value:
                signing_key = self.wallet.get_certificate_signing_key(certificate_id)
                signed = claim_value.sign(signing_key, claim_addr, certificate_id, curve=SECP256k1)
                val = signed.serialized

            if certificate_id and decoded_claim:
                signing_key = self.wallet.get_certificate_signing_key(certificate_id)
                if signing_key:
                    signed = decoded_claim.sign(signing_key,
                                                claim_addr,
                                                certificate_id,
                                                curve=SECP256k1)
                    val = signed.serialized
                else:
                    return {'success': False,
                            'reason': "Cannot sign with certificate %s" % certificate_id}

            elif not certificate_id and decoded_claim:
                if decoded_claim.has_signature:
                    certificate_id = decoded_claim.certificate_id
                    signing_key = self.wallet.get_certificate_signing_key(certificate_id)
                    if signing_key:
                        claim = ClaimDict.deserialize(val)
                        signed = claim.sign(signing_key,
                                            claim_addr,
                                            certificate_id,
                                            curve=SECP256k1)
                        val = signed.serialized
                    else:
                        return {'success': False,
                                'reason': "Cannot sign with certificate %s" % certificate_id}

        out = self._get_input_output_for_updates(name, val, amount, claim_id, txid, nout,
                                                 claim_addr, change_addr, tx_fee)
        if not out['success']:
            return out
        else:
            inputs = out['inputs']
            outputs = out['outputs']

        tx = Transaction.from_io(inputs, outputs)
        self.wallet.sign_transaction(tx, self._password)
        gl.NEED_MODIFY_CLAIM = False
        if broadcast:
            success, out = self.wallet.send_tx(tx)
            if not success:
                return {"success": False, "reason": out}

        nout = None
        amount = 0
        for i, output in enumerate(tx._outputs):
            if output[0] & TYPE_UPDATE:
                nout = i
                amount = output[2]

        return {
            "success": True,
            "txid": tx.hash(),
            "nout": nout,
            "tx": str(tx),
            "fee": str(Decimal(tx.get_fee()) / COIN),
            "amount": str(Decimal(amount) / COIN),
            "claim_id": claim_id
        }

    def _get_input_output_for_updates(self, name, val, amount, claim_id, txid, nout,
                                      claim_addr=None, change_addr=None, tx_fee=None,
                                      is_support_replace=False):
        """
        obtain inputs and outputs when crafting either an update
        or a support replacement

        :param name: (str) claim name
        :param val: (str) claim value
        :param amount: (float) claim amount, if amount is None, we keep the same amount
            as the original claim minus the tx fee
        :param claim_id: (str) claim id to be updated or if in the case of support replacements,
           claim_id of the claim that's being supported
        :param txid: (str) txid of claim to be updated
        :param nout: (int) nout of claim to be updated
        :param claim_addr: (str) specify address to send the claim to
        :param change_addr: (str) specify change address to send change to
        :param tx_fee: (float) specify amount of tx fee to pay
        :param is_support_replace: (bool) False if we are doing an update of a claim. If True,
            we are replacing a support (abandon previous support and create new
            support in place of it)

        :returns a dictionary where key 'success' is True if succesful in obtaining
            inputs and outputs, and False if not. If 'success' is False, there will
            be a 'reason' field for the failure reaso. If 'success' is True,
            there will be an 'outputs' field and 'inputs' field.
        """

        decoded_claim_id = decode_claim_id_hex(claim_id)

        if amount is not None:
            amount = int(COIN * amount)
            if amount <= 0:
                return {'success': False, 'reason': 'Amount must be greater than 0'}
        if tx_fee is not None:
            tx_fee = int(COIN * tx_fee)
            if tx_fee < 0:
                return {'success': False, 'reason': 'tx_fee must be greater than or equal to 0'}

        claim_utxo = self.wallet.get_spendable_claimtrietx_coin(txid, nout)
        if not is_support_replace and claim_utxo['is_support']:
            return {'success': False,
                    'reason': 'Cannot update a support, is_support_replace must be True'}

        inputs = [claim_utxo]
        txout_value = claim_utxo['value']

        if not is_support_replace:
            claim_tuple = ((name, decoded_claim_id, val), claim_addr)
            claim_type = TYPE_UPDATE
        else:
            # we are spending a support to make a new support
            claim_tuple = ((name, decoded_claim_id), claim_addr)
            claim_type = TYPE_SUPPORT

        # if amount is not specified, keep the same amount minus the tx fee
        if amount is None:
            dummy_outputs = [
                (
                    TYPE_ADDRESS | claim_type,
                    claim_tuple,
                    txout_value
                )
            ]
            fee = self._calculate_fee(inputs, dummy_outputs, tx_fee)
            if fee >= txout_value:
                return {
                    'success': False,
                    'reason': 'Fee will exceed amount available in original bid. Increase amount'
                }

            outputs = [
                (
                    TYPE_ADDRESS | claim_type,
                    claim_tuple,
                    txout_value - fee
                )
            ]

        elif amount <= 0:
            return {'success': False, 'reason': 'Amount must be greater than zero'}

        # amount is more than the original bid or equal, we need to get an input
        elif amount >= txout_value:
            additional_input_fee = 0
            if tx_fee is None:
                claim_input_size = Transaction.estimated_input_size(claim_utxo)
                additional_input_fee = Transaction.fee_for_size(self.wallet.relayfee(),
                                                                self.wallet.fee_per_kb(self.config),
                                                                claim_input_size)

            get_inputs_for_amount = amount - txout_value + additional_input_fee
            # create a dummy tx for the extra amount in order to get the proper inputs to spend
            dummy_outputs = [
                (
                    TYPE_ADDRESS | claim_type,
                    claim_tuple,
                    get_inputs_for_amount
                )
            ]
            coins = self.wallet.get_spendable_coins()
            try:
                dummy_tx = self.wallet.make_unsigned_transaction(coins, dummy_outputs,
                                                                 self.config, tx_fee, change_addr)
            except NotEnoughFunds:
                return {'success': False, 'reason': 'Not enough funds'}

            # add the unspents to input
            for i in dummy_tx._inputs:
                inputs.append(i)

            outputs = [
                (
                    TYPE_ADDRESS | claim_type,
                    claim_tuple,
                    amount
                )
            ]
            # add the change utxos to output
            for output in dummy_tx._outputs:
                if not output[0] & claim_type:
                    outputs.append(output)

        # amount is less than the original bid,
        # we need to put remainder minus fees in a change address
        elif amount < txout_value:

            dummy_outputs = [
                (
                    TYPE_ADDRESS | claim_type,
                    claim_tuple,
                    amount
                ),
                (
                    TYPE_ADDRESS,
                    change_addr,
                    txout_value - amount
                )
            ]
            fee = self._calculate_fee(inputs, dummy_outputs, tx_fee)
            if fee > txout_value - amount:
                return {
                    'success': False,
                    'reason': 'Fee will be greater than change amount, use amount=None to expend '
                              'change as fee'
                }

            outputs = [
                (
                    TYPE_ADDRESS | claim_type,
                    claim_tuple,
                    amount
                ),
                (
                    TYPE_ADDRESS,
                    change_addr,
                    txout_value - amount - fee
                )
            ]

        return {'success':True, 'outputs':outputs, 'inputs':inputs}

    @command('wpn')
    def abandon(self, claim_id=None, txid=None, nout=None, broadcast=True, return_addr=None,
                tx_fee=None):
        """
        Abandon a name claim

        Either specify the claim with a claim_id or with txid and nout
        """
        # gl.flag_claim = True
        claims = self.getnameclaims(raw=True, include_abandoned=False, include_supports=True,
                                    claim_id=claim_id, txid=txid, nout=nout,
                                    skip_validate_signatures=True)
        if len(claims) > 1:
            return {"success": False, 'reason': 'more than one claim that matches'}
        elif len(claims) == 0:
            return {"success": False, 'reason': 'claim not found', 'claim_id': claim_id}
        else:
            claim = claims[0]

        txid, nout = claim['txid'], claim['nout']
        if return_addr is None:
            return_addr = self.wallet.get_least_used_address()
        if tx_fee is not None:
            tx_fee = int(COIN * tx_fee)
            if tx_fee < 0:
                return {'success': False, 'reason': 'tx_fee must be greater than or equal to 0'}

        i = self.wallet.get_spendable_claimtrietx_coin(txid, nout)
        inputs = [i]
        txout_value = i['value']
        # create outputs
        outputs = [(TYPE_ADDRESS, return_addr, txout_value)]
        # fee will be roughly 10,000 deweys (0.0001 UT), standard abandon should be about 200 bytes
        # this is assuming config is not set to dynamic, which in case it will get fees from
        # ulord's fee estimation algorithm

        fee = self._calculate_fee(inputs, outputs, tx_fee)
        if fee > txout_value:
            return {'success': False, 'reason': 'transaction fee exceeds amount to abandon'}
        return_value = txout_value - fee
        # create transaction
        outputs = [(TYPE_ADDRESS, return_addr, return_value)]
        tx = Transaction.from_io(inputs, outputs)
        self.wallet.sign_transaction(tx, self._password)
        gl.NEED_MODIFY_CLAIM = False
        if broadcast:
            success, out = self.wallet.send_tx(tx)
            if not success:
                return {'success': False, 'reason': out}
        return {'success': True, 'txid': tx.hash(), 'tx': str(tx),
                'fee': str(Decimal(tx.get_fee()) / COIN)}


param_descriptions = {
    'privkey': 'Private key. Type \'?\' to get a prompt.',
    'destination': 'Bitcoin address, contact or alias',
    'address': 'Bitcoin address',
    'seed': 'Seed phrase',
    'txid': 'Transaction ID',
    'pos': 'Position',
    'height': 'Block height',
    'tx': 'Serialized transaction (hexadecimal)',
    'key': 'Variable name',
    'pubkey': 'Public key',
    'message': 'Clear text message. Use quotes if it contains spaces.',
    'encrypted': 'Encrypted message',
    'amount': 'Amount to be sent (in BTC). Type \'!\' to send the maximum available.',
    'requested_amount': 'Requested amount (in BTC).',
    'outputs': 'list of ["address", amount]',
    'exclude_claimtrietx': 'Exclude claimtrie transactions.',
    'set_default_certificate': 'Set new certificate as default signer even if there is already a '
                               'default certificate',
}

command_options = {
    'password': ("-W", "--password", "Password"),
    'receiving': (None, "--receiving", "Show only receiving addresses"),
    'change': (None, "--change", "Show only change addresses"),
    'frozen': (None, "--frozen", "Show only frozen addresses"),
    'unused': (None, "--unused", "Show only unused addresses"),
    'funded': (None, "--funded", "Show only funded addresses"),
    'show_balance': ("-b", "--balance", "Show the balances of listed addresses"),
    'show_labels': ("-l", "--labels", "Show the labels of listed addresses"),
    'nocheck': (None, "--nocheck", "Do not verify aliases"),
    'tx_fee': ("-f", "--fee", "Transaction fee (in BTC)"),
    'from_addr': ("-F", "--from",
                  "Source address. If it isn't in the wallet, it will ask for the private key "
                  "unless supplied in the format public_key:private_key. It's not saved in the "
                  "wallet."),
    'change_addr': ("-c", "--change",
                    "Change address. Default is a spare address, or the source address if it's "
                    "not in the wallet"),
    'nbits': (None, "--nbits", "Number of bits of entropy"),
    'entropy': (None, "--entropy", "Custom entropy"),
    'language': ("-L", "--lang", "Default language for wordlist"),
    'gap_limit': ("-G", "--gap", "Gap limit"),
    'privkey': (None, "--privkey", "Private key. Set to '?' to get a prompt."),
    'unsigned': ("-u", "--unsigned", "Do not sign transaction"),
    'domain': ("-D", "--domain", "List of addresses"),
    'account': (None, "--account", "Account"),
    'memo': ("-m", "--memo", "Description of the request"),
    'expiration': (None, "--expiration", "Time in seconds"),
    'force': (None, "--force", "Create new address beyong gap limit, if no more address is "
                               "available."),
    'pending': (None, "--pending", "Show only pending requests."),
    'expired': (None, "--expired", "Show only expired requests."),
    'paid': (None, "--paid", "Show only paid requests."),
    'exclude_claimtrietx': (None, "--exclude_claimtrietx", "Exclude claimtrie transactions"),
    'return_addr': (None, "--return_addr",
                    "Return address where amounts in abandoned claimtrie transactions are "
                    "returned."),
    'claim_addr': (None, "--claim_addr", "Address where claims are sent."),
    'broadcast': (None, "--broadcast", "if True, broadcast the transaction"),
    'raw': ("-r", "--raw", "if True, don't decode claim values"),
    'page': ("-p", "--page", "page number"),
    'page_size': ("-s", "--page_size", "page size"),
    'claim_id': (None, "--claim_id", "claim id"),
    'txid': ("-t", "--txid", "txid"),
    'nout': ("-n", "--nout", "nout"),
    'certificate_id': (None, "--certificate_id", "claim id of a certificate that can be used "
                                                 "for signing"),
    'skip_validate_schema': (None, "--ignore_schema", "Validate the claim conforms with unet "
                                                      "schema"),
    'set_default_certificate': (None, "--set_default_certificate",
                                "Set the new certificate as the default, even if there already is "
                                "one"),
    'amount': ("-a", "--amount", "amount to use in updated name claim"),
    'include_abandoned': (None, "--include_abandoned", "include abandoned claims"),
    'skip_validate_signatures': (None, "--skip_validate_signatures", "include abandoned claims"),
    'include_supports': (None, "--include_supports", "include supports"),
    'skip_update_check': (None, "--skip_update_check",
                          "do not check for an existing unspent claim before making a new one"),
    'revoke': (None, "--revoke", "if true, create a new signing key and revoke the old one"),
    'val': (None, '--value', 'claim value'),
    'timeout': (None, '--timeout', 'timeout'),
    'include_tip_info': (None, "--include_tip_info", 'Include claim tip information')
}


def json_loads(x):
    """don't use floats because of rounding errors"""
    return json.loads(x, parse_float=lambda x: str(Decimal(x)))

def base64_to_json(claimvalue):
    """base64 to json"""
    value = base64.b64decode(claimvalue.decode('hex'))
    return value

arg_types = {
    'num': int,
    'nbits': int,
    'entropy': long,
    'tx': json_loads,
    'pubkeys': json_loads,
    'inputs': json_loads,
    'outputs': json_loads,
    'tx_fee': lambda x: str(Decimal(x)) if x is not None else None,
    'amount': lambda x: str(Decimal(x)) if x != '!' else '!',
    'nout': int
}

config_variables = {

    'addrequest': {
        'requests_dir': 'directory where a bip70 file will be written.',
        'ssl_privkey': 'Path to your SSL private key, needed to sign the request.',
        'ssl_chain': 'Chain of SSL certificates, needed for signed requests. Put your certificate '
                     'at the top and the root CA at the end',
        'url_rewrite': 'Parameters passed to str.replace(), in order to create the r= part of '
                       'bitcoin: URIs. Example: \"(\'file:///var/www/\',\'https://unet.org/\')\"',
    },
    'listrequests': {
        'url_rewrite': 'Parameters passed to str.replace(), in order to create the r= part of '
                       'bitcoin: URIs. Example: \"(\'file:///var/www/\',\'https://unet.org/\')\"',
    }
}


def set_default_subparser(self, name, args=None):
    """
    see http://stackoverflow.com/questions/5176691/argparse-how-to-specify-a-default-subcommand
    """

    subparser_found = False
    for arg in sys.argv[1:]:
        if arg in ['-h', '--help']:  # global help if no subparser
            break
    else:
        for x in self._subparsers._actions:
            if not isinstance(x, argparse._SubParsersAction):
                continue
            for sp_name in x._name_parser_map.keys():
                if sp_name in sys.argv[1:]:
                    subparser_found = True
        if not subparser_found:
            # insert default in first position, this implies no
            # global options without a sub_parsers specified
            if args is None:
                sys.argv.insert(1, name)
            else:
                args.insert(0, name)


argparse.ArgumentParser.set_default_subparser = set_default_subparser


def add_network_options(parser):
    parser.add_argument("-1", "--oneserver", action="store_true", dest="oneserver", default=False,
                        help="connect to one server only")
    parser.add_argument("-s", "--server", dest="server", default=None,
                        help="set server host:port:protocol, where protocol is either t (tcp) or"
                             " s (ssl)")
    parser.add_argument("-p", "--proxy", dest="proxy", default=None,
                        help="set proxy [type:]host[:port], where type is socks4,socks5 or http")


def get_parser():
    # parent parser, because set_default_subparser removes global options
    parent_parser = argparse.ArgumentParser('parent', add_help=False)
    group = parent_parser.add_argument_group('global options')
    group.add_argument("-v", "--verbose", action="store_true", dest="verbose", default=False,
                       help="Show debugging information")
    group.add_argument("--client", action="store_true", dest="client", default=False,
                       help="Is it a Qt Gui client")
    group.add_argument("-P", "--portable", action="store_true", dest="portable", default=False,
                       help="Use local 'electrum_data' directory")
    group.add_argument("-w", "--wallet", dest="wallet_path", help="wallet path")
    group.add_argument("-D", "--dir", dest="uwallet_path", help="electrum directory")
    group.add_argument("--guipassword", dest="guipassword", help="The password of uwallet for Qt gui client")
    group.add_argument("--guinewpassword", dest="guinewpassword", help="The new password of uwallet for Qt gui client")
    # create main parser
    parser = argparse.ArgumentParser(
        parents=[parent_parser],
        epilog="Run 'uwallet help <command>' to see the help for a command")
    subparsers = parser.add_subparsers(dest='cmd', metavar='<command>')
    # daemon
    parser_daemon = subparsers.add_parser('daemon', parents=[parent_parser], help="Run Daemon")
    parser_daemon.add_argument("subcommand", choices=['start', 'status', 'stop'])
    # parser_daemon.set_defaults(func=run_daemon)
    add_network_options(parser_daemon)
    # commands
    for cmdname in sorted(known_commands.keys()):
        cmd = known_commands[cmdname]
        p = subparsers.add_parser(cmdname, parents=[parent_parser], help=cmd.help,
                                  description=cmd.description)
        # p.set_defaults(func=run_cmdline)
        if cmd.requires_password:
            p.add_argument("-W", "--password", dest="password", default=None, help="password")
        for optname, default in zip(cmd.options, cmd.defaults):
            a, b, help = command_options[optname]
            action = "store_true" if type(default) is bool else 'store'
            args = (a, b) if a else (b,)
            if action == 'store':
                _type = arg_types.get(optname, str)
                p.add_argument(*args, dest=optname, action=action, default=default, help=help,
                               type=_type)
            else:
                p.add_argument(*args, dest=optname, action=action, default=default, help=help)

        for param in cmd.params:
            h = param_descriptions.get(param, '')
            _type = arg_types.get(param, str)
            p.add_argument(param, help=h, type=_type)

        cvh = config_variables.get(cmdname)
        if cvh:
            group = p.add_argument_group('configuration variables',
                                         '(set with setconfig/getconfig)')
            for k, v in cvh.items():
                group.add_argument(k, nargs='?', help=v)

    # 'cmd' is the default command
    parser.set_default_subparser('cmd')
    return parser