def block_overview(request, coin_symbol, block_representation): TXNS_PER_PAGE = 20 # 1 indexed page current_page = request.GET.get('page') if current_page: current_page = int(current_page) else: current_page = 1 # TODO: fail gracefully if the user picks a number of pages that is too large # Waiting on @matthieu's change to API first (currently throws 502) try: block_details = get_block_details( block_representation=block_representation, coin_symbol=coin_symbol, txn_limit=TXNS_PER_PAGE, txn_offset=(current_page - 1) * TXNS_PER_PAGE, api_key=BLOCKCYPHER_API_KEY, ) except AssertionError: msg = _('Invalid Block Representation') messages.warning(request, msg) redir_url = reverse('coin_overview', kwargs={'coin_symbol': coin_symbol}) return HttpResponseRedirect(redir_url) # import pprint; pprint.pprint(block_details, width=1) if 'error' in block_details: msg = _('Sorry, that block was not found') messages.warning(request, msg) return HttpResponseRedirect(reverse('home')) # Technically this is not the only API call used on this page api_url = 'https://api.blockcypher.com/v1/%s/%s/blocks/%s' % ( COIN_SYMBOL_MAPPINGS[coin_symbol]['blockcypher_code'], COIN_SYMBOL_MAPPINGS[coin_symbol]['blockcypher_network'], block_representation, ) return { 'coin_symbol': coin_symbol, 'api_url': api_url, 'block_details': block_details, 'current_page': current_page, 'max_pages': get_max_pages(num_items=block_details['n_tx'], items_per_page=TXNS_PER_PAGE), }
def block_overview(request, coin_symbol, block_representation): TXNS_PER_PAGE = 20 # 1 indexed page current_page = request.GET.get('page') if current_page: current_page = int(current_page) else: current_page = 1 # TODO: fail gracefully if the user picks a number of pages that is too large # Waiting on @matthieu's change to API first (currently throws 502) try: block_details = get_block_details( block_representation=block_representation, coin_symbol=coin_symbol, txn_limit=TXNS_PER_PAGE, in_out_limit=25, txn_offset=(current_page-1)*TXNS_PER_PAGE, api_key=BLOCKCYPHER_API_KEY, ) except AssertionError: msg = _('Invalid Block Representation') messages.warning(request, msg) redir_url = reverse('coin_overview', kwargs={'coin_symbol': coin_symbol}) return HttpResponseRedirect(redir_url) # import pprint; pprint.pprint(block_details, width=1) if 'error' in block_details: msg = _('Sorry, that block was not found') messages.warning(request, msg) return HttpResponseRedirect(reverse('home')) # Technically this is not the only API call used on this page api_url = 'https://api.blockcypher.com/v1/%s/%s/blocks/%s' % ( COIN_SYMBOL_MAPPINGS[coin_symbol]['blockcypher_code'], COIN_SYMBOL_MAPPINGS[coin_symbol]['blockcypher_network'], block_representation, ) return { 'coin_symbol': coin_symbol, 'api_url': api_url, 'block_details': block_details, 'current_page': current_page, 'max_pages': get_max_pages(num_items=block_details['n_tx'], items_per_page=TXNS_PER_PAGE), }
def block_overview(request, coin_symbol, block_representation): TXNS_PER_PAGE = 5 # 1 indexed page current_page = request.GET.get('page') if current_page: current_page = int(current_page) else: current_page = 1 # TODO: fail gracefully if the user picks a number of pages that is too large # Waiting on @matthieu's change to API first (currently throws 502) block_details = get_block_details( block_representation=block_representation, coin_symbol=coin_symbol, txn_limit=TXNS_PER_PAGE, txn_offset=(current_page - 1) * TXNS_PER_PAGE, api_key=BLOCKCYPHER_API_KEY, ) # import pprint; pprint.pprint(block_details, width=1) if 'error' in block_details: msg = _('Sorry, that block was not found') messages.warning(request, msg) return HttpResponseRedirect(reverse('home')) # Technically this is not the only API call used on this page api_url = get_block_overview_url(block_representation=block_representation, coin_symbol=coin_symbol) return { 'coin_symbol': coin_symbol, 'api_url': api_url, 'block_details': block_details, 'current_page': current_page, 'max_pages': get_max_pages(num_items=block_details['n_tx'], items_per_page=TXNS_PER_PAGE), }
def block_overview(request, coin_symbol, block_representation): TXNS_PER_PAGE = 5 # 1 indexed page current_page = request.GET.get('page') if current_page: current_page = int(current_page) else: current_page = 1 # TODO: fail gracefully if the user picks a number of pages that is too large # Waiting on @matthieu's change to API first (currently throws 502) block_details = get_block_details( block_representation=block_representation, coin_symbol=coin_symbol, txn_limit=TXNS_PER_PAGE, txn_offset=(current_page-1)*TXNS_PER_PAGE, api_key=BLOCKCYPHER_API_KEY, ) # import pprint; pprint.pprint(block_details, width=1) if 'error' in block_details: msg = _('Sorry, that block was not found') messages.warning(request, msg) return HttpResponseRedirect(reverse('home')) # Technically this is not the only API call used on this page api_url = get_block_overview_url(block_representation=block_representation, coin_symbol=coin_symbol) return { 'coin_symbol': coin_symbol, 'api_url': api_url, 'block_details': block_details, 'current_page': current_page, 'max_pages': get_max_pages(num_items=block_details['n_tx'], items_per_page=TXNS_PER_PAGE), }
def address_overview(request, coin_symbol, address, wallet_name=None): TXNS_PER_PAGE = 100 # 1 indexed page current_page = request.GET.get('page') if current_page: current_page = int(current_page) else: current_page = 1 try: address_details = get_address_details( address=address, coin_symbol=coin_symbol, txn_limit=TXNS_PER_PAGE, api_key=BLOCKCYPHER_API_KEY, ) except AssertionError: msg = _('Invalid Address') messages.warning(request, msg) redir_url = reverse('coin_overview', kwargs={'coin_symbol': coin_symbol}) return HttpResponseRedirect(redir_url) # import pprint; pprint.pprint(address_details, width=1) if 'error' in address_details: msg = _('Sorry, that address was not found') messages.warning(request, msg) return HttpResponseRedirect(reverse('home')) if request.user.is_authenticated(): # notify user on page of any forwarding or subscriptions they may have for address_subscription in AddressSubscription.objects.filter( auth_user=request.user, b58_address=address, coin_symbol=coin_symbol, unsubscribed_at=None, ): if address_subscription.auth_user.email_verified: msg = _('Private Message: you are subscribed to this address and will receive email notifications at <b>%(user_email)s</b> (<a href="%(unsub_url)s">unsubscribe</a>)' % { 'user_email': request.user.email, 'unsub_url': reverse('user_unsubscribe_address', kwargs={ 'address_subscription_id': address_subscription.id, }), }) messages.info(request, msg, extra_tags='safe') else: msg = _('Private Message: you are not subscribed to this address because you have not clicked the link sent to <b>%(user_email)s</b>' % { 'user_email': request.user.email, }) messages.error(request, msg, extra_tags='safe') print('ERROR') # there can be only one af_initial = get_object_or_None(AddressForwarding, auth_user=request.user, initial_address=address, coin_symbol=coin_symbol, ) if af_initial: msg = _(''' Private Message: this address will automatically forward to <a href="%(destination_addr_uri)s">%(destination_address)s</a> any time a payment is received. <br /><br /> <i>%(small_payments_msg)s</i> ''' % { 'destination_address': af_initial.destination_address, 'destination_addr_uri': reverse('address_overview', kwargs={ 'address': af_initial.destination_address, 'coin_symbol': coin_symbol, }), 'small_payments_msg': SMALL_PAYMENTS_MSG, }) messages.info(request, msg, extra_tags='safe') # There could be many for af_destination in AddressForwarding.objects.filter( auth_user=request.user, destination_address=address, coin_symbol=coin_symbol, ): msg = _(''' Private Message: this address will automatically receive forwarded transactions from <a href="%(initial_addr_uri)s">%(initial_address)s</a>. <br /><br /> <i>%(small_payments_msg)s</i> ''' % { 'initial_address': af_destination.initial_address, 'initial_addr_uri': reverse('address_overview', kwargs={ 'address': af_destination.initial_address, 'coin_symbol': coin_symbol, }), 'small_payments_msg': SMALL_PAYMENTS_MSG, }) messages.info(request, msg, extra_tags='safe') all_transactions = address_details.get('unconfirmed_txrefs', []) + address_details.get('txrefs', []) # transaction pagination: 0-indexed and inclusive tx_start_num = (current_page - 1) * TXNS_PER_PAGE tx_end_num = current_page * TXNS_PER_PAGE - 1 # filter address details for pagination. HACK! all_transactions = all_transactions[tx_start_num:tx_end_num] flattened_txs = flatten_txns_by_hash(all_transactions, nesting=False) api_url = 'https://api.blockcypher.com/v1/%s/%s/addrs/%s' % ( COIN_SYMBOL_MAPPINGS[coin_symbol]['blockcypher_code'], COIN_SYMBOL_MAPPINGS[coin_symbol]['blockcypher_network'], address) return { 'coin_symbol': coin_symbol, 'address': address, 'api_url': api_url, 'wallet_name': wallet_name, 'current_page': current_page, 'max_pages': get_max_pages(num_items=address_details['final_n_tx'], items_per_page=TXNS_PER_PAGE), 'total_sent_satoshis': address_details['total_sent'], 'total_received_satoshis': address_details['total_received'], 'unconfirmed_balance_satoshis': address_details['unconfirmed_balance'], 'confirmed_balance_satoshis': address_details['balance'], 'total_balance_satoshis': address_details['final_balance'], 'flattened_txs': flattened_txs, 'num_confirmed_txns': address_details['n_tx'], 'num_unconfirmed_txns': address_details['unconfirmed_n_tx'], 'num_all_txns': address_details['final_n_tx'], 'BLOCKCYPHER_PUBLIC_KEY': BLOCKCYPHER_PUBLIC_KEY, }
def address_overview(request, coin_symbol, address, wallet_name=None): TXNS_PER_PAGE = 100 # 1 indexed page current_page = request.GET.get('page') if current_page: current_page = int(current_page) else: current_page = 1 try: address_details = get_address_details( address=address, coin_symbol=coin_symbol, txn_limit=5000, api_key=BLOCKCYPHER_API_KEY, ) except AssertionError: msg = _('Invalid Address') messages.warning(request, msg) redir_url = reverse('coin_overview', kwargs={'coin_symbol': coin_symbol}) return HttpResponseRedirect(redir_url) #import pprint; pprint.pprint(address_details, width=1) if 'error' in address_details: msg = _('Sorry, that address was not found') messages.warning(request, msg) return HttpResponseRedirect(reverse('home')) all_transactions = address_details.get('unconfirmed_txrefs', []) + address_details.get('txrefs', []) # doesn't cover pagination confirmed_sent_satoshis, confirmed_received_satoshis = 0, 0 unconfirmed_sent_satoshis, unconfirmed_received_satoshis = 0, 0 for transaction in all_transactions: if transaction['tx_input_n'] >= 0: # It's sent if transaction['confirmations'] > 6: confirmed_sent_satoshis += transaction['value'] else: unconfirmed_sent_satoshis += transaction['value'] else: # It's received if transaction['confirmations'] > 6: confirmed_received_satoshis += transaction['value'] else: unconfirmed_received_satoshis += transaction['value'] # transaction pagination: 0-indexed and inclusive tx_start_num = (current_page - 1) * TXNS_PER_PAGE tx_end_num = current_page * TXNS_PER_PAGE - 1 # filter address details for pagination. HACK! all_transactions = all_transactions[tx_start_num:tx_end_num] all_txids = set([tx['tx_hash'] for tx in all_transactions]) return { 'coin_symbol': coin_symbol, 'address': address, 'api_url': get_address_details_url(address=address, coin_symbol=coin_symbol), 'wallet_name': wallet_name, 'current_page': current_page, 'max_pages': get_max_pages(num_items=address_details['final_n_tx'], items_per_page=TXNS_PER_PAGE), 'confirmed_sent_satoshis': confirmed_sent_satoshis, 'unconfirmed_sent_satoshis': unconfirmed_sent_satoshis, 'total_sent_satoshis': unconfirmed_sent_satoshis + confirmed_sent_satoshis, 'confirmed_received_satoshis': confirmed_received_satoshis, 'unconfirmed_received_satoshis': unconfirmed_received_satoshis, 'total_received_satoshis': unconfirmed_received_satoshis + confirmed_received_satoshis, 'unconfirmed_balance_satoshis': address_details['unconfirmed_balance'], 'confirmed_balance_satoshis': address_details['balance'], 'total_balance_satoshis': address_details['final_balance'], 'all_transactions': all_transactions, 'num_confirmed_txns': address_details['n_tx'], 'num_unconfirmed_txns': address_details['unconfirmed_n_tx'], 'num_all_txns': address_details['final_n_tx'], 'has_more': bool(len(all_txids) != address_details['final_n_tx']), 'BLOCKCYPHER_PUBLIC_KEY': BLOCKCYPHER_PUBLIC_KEY, }
def address_overview(request, coin_symbol, address, wallet_name=None): TXNS_PER_PAGE = 100 # 1 indexed page current_page = request.GET.get('page') if current_page: current_page = int(current_page) else: current_page = 1 try: address_details = get_address_details( address=address, coin_symbol=coin_symbol, txn_limit=TXNS_PER_PAGE, api_key=BLOCKCYPHER_API_KEY, ) except AssertionError: msg = _('Invalid Address') messages.warning(request, msg) redir_url = reverse('coin_overview', kwargs={'coin_symbol': coin_symbol}) return HttpResponseRedirect(redir_url) # import pprint; pprint.pprint(address_details, width=1) if 'error' in address_details: msg = _('Sorry, that address was not found') messages.warning(request, msg) return HttpResponseRedirect(reverse('home')) if request.user.is_authenticated(): # notify user on page of any forwarding or subscriptions they may have for address_subscription in AddressSubscription.objects.filter( auth_user=request.user, b58_address=address, coin_symbol=coin_symbol, unsubscribed_at=None, ): if address_subscription.auth_user.email_verified: msg = _( 'Private Message: you are subscribed to this address and will receive email notifications at <b>%(user_email)s</b> (<a href="%(unsub_url)s">unsubscribe</a>)' % { 'user_email': request.user.email, 'unsub_url': reverse('user_unsubscribe_address', kwargs={ 'address_subscription_id': address_subscription.id, }), }) messages.info(request, msg, extra_tags='safe') else: msg = _( 'Private Message: you are not subscribed to this address because you have not clicked the link sent to <b>%(user_email)s</b>' % { 'user_email': request.user.email, }) messages.error(request, msg, extra_tags='safe') print('ERROR') # there can be only one af_initial = get_object_or_None( AddressForwarding, auth_user=request.user, initial_address=address, coin_symbol=coin_symbol, ) if af_initial: msg = _( ''' Private Message: this address will automatically forward to <a href="%(destination_addr_uri)s">%(destination_address)s</a> any time a payment is received. <br /><br /> <i>%(small_payments_msg)s</i> ''' % { 'destination_address': af_initial.destination_address, 'destination_addr_uri': reverse('address_overview', kwargs={ 'address': af_initial.destination_address, 'coin_symbol': coin_symbol, }), 'small_payments_msg': SMALL_PAYMENTS_MSG, }) messages.info(request, msg, extra_tags='safe') # There could be many for af_destination in AddressForwarding.objects.filter( auth_user=request.user, destination_address=address, coin_symbol=coin_symbol, ): msg = _( ''' Private Message: this address will automatically receive forwarded transactions from <a href="%(initial_addr_uri)s">%(initial_address)s</a>. <br /><br /> <i>%(small_payments_msg)s</i> ''' % { 'initial_address': af_destination.initial_address, 'initial_addr_uri': reverse('address_overview', kwargs={ 'address': af_destination.initial_address, 'coin_symbol': coin_symbol, }), 'small_payments_msg': SMALL_PAYMENTS_MSG, }) messages.info(request, msg, extra_tags='safe') all_transactions = address_details.get( 'unconfirmed_txrefs', []) + address_details.get('txrefs', []) # transaction pagination: 0-indexed and inclusive tx_start_num = (current_page - 1) * TXNS_PER_PAGE tx_end_num = current_page * TXNS_PER_PAGE - 1 # filter address details for pagination. HACK! all_transactions = all_transactions[tx_start_num:tx_end_num] flattened_txs = flatten_txns_by_hash(all_transactions, nesting=False) api_url = 'https://api.blockcypher.com/v1/%s/%s/addrs/%s' % ( COIN_SYMBOL_MAPPINGS[coin_symbol]['blockcypher_code'], COIN_SYMBOL_MAPPINGS[coin_symbol]['blockcypher_network'], address) return { 'coin_symbol': coin_symbol, 'address': address, 'api_url': api_url, 'wallet_name': wallet_name, 'current_page': current_page, 'max_pages': get_max_pages(num_items=address_details['final_n_tx'], items_per_page=TXNS_PER_PAGE), 'total_sent_satoshis': address_details['total_sent'], 'total_received_satoshis': address_details['total_received'], 'unconfirmed_balance_satoshis': address_details['unconfirmed_balance'], 'confirmed_balance_satoshis': address_details['balance'], 'total_balance_satoshis': address_details['final_balance'], 'flattened_txs': flattened_txs, 'num_confirmed_txns': address_details['n_tx'], 'num_unconfirmed_txns': address_details['unconfirmed_n_tx'], 'num_all_txns': address_details['final_n_tx'], 'BLOCKCYPHER_PUBLIC_KEY': BLOCKCYPHER_PUBLIC_KEY, }
def wallet_overview(request, coin_symbol, pubkey): subchain_indices = request.GET.get('subchain-indices') if subchain_indices: subchain_indices = subchain_indices.split('-') if subchain_indices == ['']: subchain_indices = [] else: subchain_indices = [int(x) for x in subchain_indices] # TODO: confirm it's a pubkey and not a privkey TXNS_PER_PAGE = 100 # 1 indexed page current_page = request.GET.get('page') if current_page: current_page = int(current_page) else: current_page = 1 # transaction pagination: 0-indexed and inclusive tx_start_num = (current_page - 1) * TXNS_PER_PAGE tx_end_num = current_page * TXNS_PER_PAGE - 1 wallet_name = get_blockcypher_walletname_from_mpub(mpub=pubkey, subchain_indices=subchain_indices) # TODO: could store in DB whether created or not create_hd_wallet( wallet_name=wallet_name, xpubkey=pubkey, api_key=BLOCKCYPHER_API_KEY, subchain_indices=subchain_indices, coin_symbol=coin_symbol, ) wallet_details = get_wallet_transactions( wallet_name=wallet_name, api_key=BLOCKCYPHER_API_KEY, coin_symbol=coin_symbol, txn_limit=TXNS_PER_PAGE, ) # import pprint; pprint.pprint(wallet_details, width=1) assert 'error' not in wallet_details, wallet_details all_transactions = wallet_details.get('unconfirmed_txrefs', []) + wallet_details.get('txrefs', []) # filter address details for pagination. HACK! all_transactions = all_transactions[tx_start_num:tx_end_num] flattened_txs = flatten_txns_by_hash(all_transactions, nesting=False) return { 'is_wallet_page': True, # shared template 'coin_symbol': coin_symbol, 'pubkey': pubkey, 'subchain_indices': subchain_indices, 'current_page': current_page, 'max_pages': get_max_pages(num_items=wallet_details['final_n_tx'], items_per_page=TXNS_PER_PAGE), 'total_sent_satoshis': wallet_details['total_sent'], 'total_received_satoshis': wallet_details['total_received'], 'unconfirmed_balance_satoshis': wallet_details['unconfirmed_balance'], 'confirmed_balance_satoshis': wallet_details['balance'], 'total_balance_satoshis': wallet_details['final_balance'], 'flattened_txs': flattened_txs, 'num_confirmed_txns': wallet_details['n_tx'], 'num_unconfirmed_txns': wallet_details['unconfirmed_n_tx'], 'num_all_txns': wallet_details['final_n_tx'], }
def address_overview(request, coin_symbol, address): TXNS_PER_PAGE = 100 # 1 indexed page current_page = request.GET.get('page') if current_page: current_page = int(current_page) else: current_page = 1 address_details = get_address_details( address=address, coin_symbol=coin_symbol, txn_limit=5000, api_key=BLOCKCYPHER_API_KEY, ) #import pprint; pprint.pprint(address_details, width=1) if 'error' in address_details: msg = _('Sorry, that address was not found') messages.warning(request, msg) return HttpResponseRedirect(reverse('home')) all_transactions = address_details.get('unconfirmed_txrefs', []) + address_details.get('txrefs', []) # doesn't cover pagination confirmed_sent_satoshis, confirmed_received_satoshis = 0, 0 unconfirmed_sent_satoshis, unconfirmed_received_satoshis = 0, 0 for transaction in all_transactions: if transaction['tx_input_n'] >= 0: # It's sent if transaction['confirmations'] > 6: confirmed_sent_satoshis += transaction['value'] else: unconfirmed_sent_satoshis += transaction['value'] else: # It's received if transaction['confirmations'] > 6: confirmed_received_satoshis += transaction['value'] else: unconfirmed_received_satoshis += transaction['value'] # transaction pagination: 0-indexed and inclusive tx_start_num = (current_page - 1) * TXNS_PER_PAGE tx_end_num = current_page * TXNS_PER_PAGE - 1 # filter address details for pagination. HACK! all_transactions = all_transactions[tx_start_num:tx_end_num] api_url = get_address_details_url(address=address, coin_symbol=coin_symbol) all_txids = set([tx['tx_hash'] for tx in all_transactions]) return { 'coin_symbol': coin_symbol, 'address': address, 'api_url': api_url, 'current_page': current_page, 'max_pages': get_max_pages(num_items=address_details['final_n_tx'], items_per_page=TXNS_PER_PAGE), 'confirmed_sent_satoshis': confirmed_sent_satoshis, 'unconfirmed_sent_satoshis': unconfirmed_sent_satoshis, 'total_sent_satoshis': unconfirmed_sent_satoshis + confirmed_sent_satoshis, 'confirmed_received_satoshis': confirmed_received_satoshis, 'unconfirmed_received_satoshis': unconfirmed_received_satoshis, 'total_received_satoshis': unconfirmed_received_satoshis + confirmed_received_satoshis, 'unconfirmed_balance_satoshis': address_details['unconfirmed_balance'], 'confirmed_balance_satoshis': address_details['balance'], 'total_balance_satoshis': address_details['final_balance'], 'all_transactions': all_transactions, 'num_confirmed_txns': address_details['n_tx'], 'num_unconfirmed_txns': address_details['unconfirmed_n_tx'], 'num_all_txns': address_details['final_n_tx'], 'has_more': bool(len(all_txids) != address_details['final_n_tx']), 'BLOCKCYPHER_PUBLIC_KEY': BLOCKCYPHER_PUBLIC_KEY, }
def wallet_overview(request, coin_symbol, pubkey): subchain_indices = request.GET.get('subchain-indices') if subchain_indices: subchain_indices = subchain_indices.split('-') if subchain_indices == ['']: subchain_indices = [] else: subchain_indices = [int(x) for x in subchain_indices] # TODO: confirm it's a pubkey and not a privkey TXNS_PER_PAGE = 100 # 1 indexed page current_page = request.GET.get('page') if current_page: current_page = int(current_page) else: current_page = 1 # transaction pagination: 0-indexed and inclusive tx_start_num = (current_page - 1) * TXNS_PER_PAGE tx_end_num = current_page * TXNS_PER_PAGE - 1 wallet_name = get_blockcypher_walletname_from_mpub( mpub=pubkey, subchain_indices=subchain_indices) # TODO: could store in DB whether created or not create_hd_wallet( wallet_name=wallet_name, xpubkey=pubkey, api_key=BLOCKCYPHER_API_KEY, subchain_indices=subchain_indices, coin_symbol=coin_symbol, ) wallet_details = get_wallet_details( wallet_name=wallet_name, coin_symbol=coin_symbol, txn_limit=TXNS_PER_PAGE, api_key=BLOCKCYPHER_API_KEY, ) #import pprint; pprint.pprint(wallet_details, width=1) assert 'error' not in wallet_details, wallet_details all_transactions = wallet_details.get( 'unconfirmed_txrefs', []) + wallet_details.get('txrefs', []) # filter address details for pagination. HACK! all_transactions = all_transactions[tx_start_num:tx_end_num] return { 'is_wallet_page': True, # shared template 'coin_symbol': coin_symbol, 'pubkey': pubkey, 'subchain_indices': subchain_indices, 'current_page': current_page, 'max_pages': get_max_pages(num_items=wallet_details['final_n_tx'], items_per_page=TXNS_PER_PAGE), 'total_sent_satoshis': wallet_details['total_sent'], 'total_received_satoshis': wallet_details['total_received'], 'unconfirmed_balance_satoshis': wallet_details['unconfirmed_balance'], 'confirmed_balance_satoshis': wallet_details['balance'], 'total_balance_satoshis': wallet_details['final_balance'], 'all_transactions': all_transactions, 'num_confirmed_txns': wallet_details['n_tx'], 'num_unconfirmed_txns': wallet_details['unconfirmed_n_tx'], 'num_all_txns': wallet_details['final_n_tx'], }