diff --git a/lbry/lbry/extras/daemon/Daemon.py b/lbry/lbry/extras/daemon/Daemon.py index 3b5df160a..a40ea0fa5 100644 --- a/lbry/lbry/extras/daemon/Daemon.py +++ b/lbry/lbry/extras/daemon/Daemon.py @@ -14,7 +14,7 @@ from typing import Callable, Optional, List from binascii import hexlify, unhexlify from traceback import format_exc from aiohttp import web -from functools import wraps +from functools import wraps, partial from google.protobuf.message import DecodeError from torba.client.wallet import Wallet from torba.client.baseaccount import SingleKey, HierarchicalDeterministic @@ -1044,8 +1044,22 @@ class Daemon(metaclass=JSONRPCServerType): (decimal) amount of lbry credits in wallet """ account = self.get_account_or_default(account_id) - dewies = await account.get_balance(confirmations=confirmations) - return dewies_to_lbc(dewies) + get_balance = partial(account.get_balance, confirmations=True) + claims_balance = await get_balance(include_claims=True, claim_type__or={'is_claim':True, 'is_update': True}) + supports_balance = await get_balance(include_claims=True, is_support=True) + total = await get_balance(include_claims=True) + unavailable = claims_balance + supports_balance + return { + 'total': dewies_to_lbc(total), + 'available': dewies_to_lbc(total - unavailable), + 'reserved': { + 'total': dewies_to_lbc(unavailable), + 'claims': dewies_to_lbc(claims_balance), + 'supports': dewies_to_lbc(supports_balance) + }, + 'tips_received': '0.0', + 'tips_sent': '0.0' + } @requires("wallet") async def jsonrpc_account_add( diff --git a/lbry/tests/integration/test_chris45.py b/lbry/tests/integration/test_chris45.py index e0a77d262..88cf5746f 100644 --- a/lbry/tests/integration/test_chris45.py +++ b/lbry/tests/integration/test_chris45.py @@ -10,7 +10,7 @@ class EpicAdventuresOfChris45(CommandTestCase): # Chris45 starts everyday by checking his balance. result = await self.daemon.jsonrpc_account_balance() - self.assertEqual(result, '10.0') + self.assertEqual(result['available'], '10.0') # "10 LBC, yippy! I can do a lot with that.", he thinks to himself, # enthusiastically. But he is hungry so he goes into the kitchen # to make himself a spamdwich. @@ -31,12 +31,12 @@ class EpicAdventuresOfChris45(CommandTestCase): # Chris doesn't sit idly by: he checks his balance! result = await self.daemon.jsonrpc_account_balance() - self.assertEqual(result, '8.989893') + self.assertEqual(result['available'], '8.989893') # He waits for 6 more blocks (confirmations) to make sure the balance has been settled. await self.generate(6) result = await self.daemon.jsonrpc_account_balance(confirmations=6) - self.assertEqual(result, '8.989893') + self.assertEqual(result['available'], '8.989893') # And is the channel resolvable and empty? response = await self.resolve('lbry://@spam') @@ -59,7 +59,7 @@ class EpicAdventuresOfChris45(CommandTestCase): # He quickly checks the unconfirmed balance to make sure everything looks # correct. result = await self.daemon.jsonrpc_account_balance() - self.assertEqual(result, '7.969786') + self.assertEqual(result['available'], '7.969786') # Also checks that his new story can be found on the blockchain before # giving the link to all his friends. @@ -70,7 +70,7 @@ class EpicAdventuresOfChris45(CommandTestCase): await self.generate(5) # When he comes back he verifies the confirmed balance. result = await self.daemon.jsonrpc_account_balance() - self.assertEqual(result, '7.969786') + self.assertEqual(result['available'], '7.969786') # As people start reading his story they discover some typos and notify # Chris who explains in despair "Oh! Noooooos!" but then remembers @@ -93,7 +93,7 @@ class EpicAdventuresOfChris45(CommandTestCase): # After abandoning he just waits for his LBCs to be returned to his account await self.generate(5) result = await self.daemon.jsonrpc_account_balance() - self.assertEqual(result, '8.9693455') + self.assertEqual(result['available'], '8.9693455') # Amidst all this Chris receives a call from his friend Ramsey # who says that it is of utmost urgency that Chris transfer him @@ -109,11 +109,11 @@ class EpicAdventuresOfChris45(CommandTestCase): await self.generate(5) result = await self.daemon.jsonrpc_account_balance() # Chris' balance was correct - self.assertEqual(result, '7.9692215') + self.assertEqual(result['available'], '7.9692215') # Ramsey too assured him that he had received the 1 LBC and thanks him result = await self.daemon.jsonrpc_account_balance(ramsey_account_id) - self.assertEqual(result, '1.0') + self.assertEqual(result['available'], '1.0') # After Chris is done with all the "helping other people" stuff he decides that it's time to # write a new story and publish it to lbry. All he needed was a fresh start and he came up with: diff --git a/lbry/tests/integration/test_claim_commands.py b/lbry/tests/integration/test_claim_commands.py index 7eec987de..25f23c498 100644 --- a/lbry/tests/integration/test_claim_commands.py +++ b/lbry/tests/integration/test_claim_commands.py @@ -602,15 +602,15 @@ class StreamCommands(ClaimTestCase): account2_id, account2 = new_account['id'], self.daemon.get_account_or_error(new_account['id']) await self.out(self.channel_create('@spam', '1.0')) - self.assertEqual('8.989893', await self.daemon.jsonrpc_account_balance()) + self.assertEqual('8.989893', (await self.daemon.jsonrpc_account_balance())['available']) result = await self.out(self.daemon.jsonrpc_account_send( '5.0', await self.daemon.jsonrpc_address_unused(account2_id) )) await self.confirm_tx(result['txid']) - self.assertEqual('3.989769', await self.daemon.jsonrpc_account_balance()) - self.assertEqual('5.0', await self.daemon.jsonrpc_account_balance(account2_id)) + self.assertEqual('3.989769', (await self.daemon.jsonrpc_account_balance())['available']) + self.assertEqual('5.0', (await self.daemon.jsonrpc_account_balance(account2_id))['available']) baz_tx = await self.out(self.channel_create('@baz', '1.0', account_id=account2_id)) baz_id = self.get_claim_id(baz_tx) diff --git a/lbry/tests/integration/test_transaction_commands.py b/lbry/tests/integration/test_transaction_commands.py index a7f624650..fecc5325d 100644 --- a/lbry/tests/integration/test_transaction_commands.py +++ b/lbry/tests/integration/test_transaction_commands.py @@ -36,3 +36,32 @@ class TransactionCommandsTestCase(CommandTestCase): await self.assertBalance(self.account, '0.0') await self.daemon.jsonrpc_utxo_release() await self.assertBalance(self.account, '11.0') + + async def test_granular_balances(self): + initial_balance = await self.daemon.jsonrpc_account_balance() + self.assertEqual({ + 'tips_received': '0.0', + 'tips_sent': '0.0', + 'total': '10.0', + 'available': '10.0', + 'reserved': {'total': '0.0', 'claims': '0.0', 'supports': '0.0'} + }, initial_balance) + first_claim_id = self.get_claim_id(await self.stream_create('granularity', bid='3.0')) + await self.stream_update(first_claim_id, data=b'news', bid='1.0') + await self.support_create(first_claim_id, bid='2.0') + second_account_id = (await self.out(self.daemon.jsonrpc_account_create("Tip-er")))['id'] + second_accound_address = await self.daemon.jsonrpc_address_unused(second_account_id) + await self.confirm_tx((await self.daemon.jsonrpc_account_send('1.0', second_accound_address)).id) + second_claim_id = self.get_claim_id(await self.stream_create( + name='granularity-is-cool', account_id=second_account_id, bid='0.1')) + await self.daemon.jsonrpc_support_create(second_claim_id, '0.5', tip=True) + await self.confirm_tx((await self.daemon.jsonrpc_support_create( + first_claim_id, '0.3', tip=True, account_id=second_account_id)).id) + final_balance = await self.daemon.jsonrpc_account_balance() + self.assertEqual({ + 'tips_received': '0.0', + 'tips_sent': '0.0', + 'total': '8.777264', + 'available': '5.477264', + 'reserved': {'claims': '1.0', 'supports': '2.3', 'total': '3.3'} + }, final_balance)