added wallet balance command

This commit is contained in:
Lex Berezhny 2019-10-13 19:32:10 -04:00
parent fea7275148
commit e2b92c99ef
5 changed files with 105 additions and 19 deletions

View file

@ -38,7 +38,7 @@ from lbry.extras.daemon import comment_client
from lbry.extras.daemon.undecorated import undecorated from lbry.extras.daemon.undecorated import undecorated
from lbry.wallet.transaction import Transaction, Output, Input from lbry.wallet.transaction import Transaction, Output, Input
from lbry.wallet.account import Account as LBCAccount from lbry.wallet.account import Account as LBCAccount
from lbry.wallet.dewies import dewies_to_lbc, lbc_to_dewies from lbry.wallet.dewies import dewies_to_lbc, lbc_to_dewies, dict_values_to_lbc
from lbry.schema.claim import Claim from lbry.schema.claim import Claim
from lbry.schema.url import URL from lbry.schema.url import URL
@ -1141,6 +1141,31 @@ class Daemon(metaclass=JSONRPCServerType):
self.wallet_manager.wallets.remove(wallet) self.wallet_manager.wallets.remove(wallet)
return wallet return wallet
@requires("wallet")
async def jsonrpc_wallet_balance(self, wallet_id=None, confirmations=0, reserved_subtotals=False):
"""
Return the balance of a wallet
Usage:
wallet_balance [--wallet_id=<wallet_id>] [--confirmations=<confirmations>] [--reserved_subtotals]
Options:
--wallet_id=<wallet_id> : (str) balance for specific wallet
--confirmations=<confirmations> : (int) Only include transactions with this many
confirmed blocks.
--reserved_subtotals : (bool) Include detailed reserved balances on
claims, tips and supports.
Returns:
(decimal) amount of lbry credits in wallet
"""
wallet = self.wallet_manager.get_wallet_or_default(wallet_id)
balance = await self.ledger.get_detailed_balance(
accounts=wallet.accounts, confirmations=confirmations,
reserved_subtotals=reserved_subtotals
)
return dict_values_to_lbc(balance)
ACCOUNT_DOC = """ ACCOUNT_DOC = """
Create, modify and inspect wallet accounts. Create, modify and inspect wallet accounts.
""" """
@ -1200,7 +1225,10 @@ class Daemon(metaclass=JSONRPCServerType):
""" """
wallet = self.wallet_manager.get_wallet_or_default(wallet_id) wallet = self.wallet_manager.get_wallet_or_default(wallet_id)
account = wallet.get_account_or_default(account_id) account = wallet.get_account_or_default(account_id)
return await account.get_granular_balances(confirmations=confirmations, reserved_subtotals=reserved_subtotals) balance = await account.get_detailed_balance(
confirmations=confirmations, reserved_subtotals=reserved_subtotals
)
return dict_values_to_lbc(balance)
@requires("wallet") @requires("wallet")
async def jsonrpc_account_add( async def jsonrpc_account_add(

View file

@ -5,7 +5,6 @@ from hashlib import sha256
from string import hexdigits from string import hexdigits
import ecdsa import ecdsa
from lbry.wallet.dewies import dewies_to_lbc
from lbry.wallet.constants import TXO_TYPES from lbry.wallet.constants import TXO_TYPES
from torba.client.baseaccount import BaseAccount, HierarchicalDeterministic from torba.client.baseaccount import BaseAccount, HierarchicalDeterministic
@ -78,7 +77,7 @@ class Account(BaseAccount):
constraints.update({'txo_type': 0}) constraints.update({'txo_type': 0})
return super().get_balance(confirmations, **constraints) return super().get_balance(confirmations, **constraints)
async def get_granular_balances(self, confirmations=0, reserved_subtotals=False): async def get_detailed_balance(self, confirmations=0, reserved_subtotals=False):
tips_balance, supports_balance, claims_balance = 0, 0, 0 tips_balance, supports_balance, claims_balance = 0, 0, 0
get_total_balance = partial(self.get_balance, confirmations=confirmations, include_claims=True) get_total_balance = partial(self.get_balance, confirmations=confirmations, include_claims=True)
total = await get_total_balance() total = await get_total_balance()
@ -98,13 +97,13 @@ class Account(BaseAccount):
confirmations=confirmations, include_claims=True, txo_type__gt=0 confirmations=confirmations, include_claims=True, txo_type__gt=0
) )
return { return {
'total': dewies_to_lbc(total), 'total': total,
'available': dewies_to_lbc(total - reserved), 'available': total - reserved,
'reserved': dewies_to_lbc(reserved), 'reserved': reserved,
'reserved_subtotals': { 'reserved_subtotals': {
'claims': dewies_to_lbc(claims_balance), 'claims': claims_balance,
'supports': dewies_to_lbc(supports_balance), 'supports': supports_balance,
'tips': dewies_to_lbc(tips_balance) 'tips': tips_balance
} if reserved_subtotals else None } if reserved_subtotals else None
} }

View file

@ -31,3 +31,12 @@ def lbc_to_dewies(lbc: str) -> int:
def dewies_to_lbc(dewies) -> str: def dewies_to_lbc(dewies) -> str:
return satoshis_to_coins(dewies) return satoshis_to_coins(dewies)
def dict_values_to_lbc(d):
for key, value in d.items():
if isinstance(value, int):
d[key] = dewies_to_lbc(value)
elif isinstance(value, dict):
dict_values_to_lbc(value)
return d

View file

@ -244,6 +244,23 @@ class MainNetLedger(BaseLedger):
def get_transaction_history_count(self, **constraints): def get_transaction_history_count(self, **constraints):
return self.db.get_transaction_count(**constraints) return self.db.get_transaction_count(**constraints)
@staticmethod
async def get_detailed_balance(accounts, confirmations=0, reserved_subtotals=False):
result = {}
for account in accounts:
balance = await account.get_detailed_balance(confirmations, reserved_subtotals)
if result:
for key, value in balance.items():
if key == 'reserved_subtotals':
if value is not None:
for subkey, subvalue in value.items():
result['reserved_subtotals'][subkey] += subvalue
else:
result[key] += value
else:
result = balance
return result
class TestNetLedger(MainNetLedger): class TestNetLedger(MainNetLedger):
network_name = 'testnet' network_name = 'testnet'

View file

@ -38,34 +38,42 @@ class TransactionCommandsTestCase(CommandTestCase):
await self.assertBalance(self.account, '11.0') await self.assertBalance(self.account, '11.0')
async def test_granular_balances(self): async def test_granular_balances(self):
account_balance = self.daemon.jsonrpc_account_balance account2 = await self.daemon.jsonrpc_account_create("Tip-er")
self.assertEqual(await account_balance(reserved_subtotals=False), { account_balance = self.daemon.jsonrpc_account_balance
wallet_balance = self.daemon.jsonrpc_wallet_balance
expected = {
'total': '10.0', 'total': '10.0',
'available': '10.0', 'available': '10.0',
'reserved': '0.0', 'reserved': '0.0',
'reserved_subtotals': None 'reserved_subtotals': None
}) }
self.assertEqual(await account_balance(reserved_subtotals=False), expected)
self.assertEqual(await wallet_balance(reserved_subtotals=False), expected)
self.assertEqual(await account_balance(reserved_subtotals=True), { expected = {
'total': '10.0', 'total': '10.0',
'available': '10.0', 'available': '10.0',
'reserved': '0.0', 'reserved': '0.0',
'reserved_subtotals': {'claims': '0.0', 'supports': '0.0', 'tips': '0.0'} 'reserved_subtotals': {'claims': '0.0', 'supports': '0.0', 'tips': '0.0'}
}) }
self.assertEqual(await account_balance(reserved_subtotals=True), expected)
self.assertEqual(await wallet_balance(reserved_subtotals=True), expected)
# claim with update + supporting our own claim # claim with update + supporting our own claim
stream1 = await self.stream_create('granularity', '3.0') stream1 = await self.stream_create('granularity', '3.0')
await self.stream_update(self.get_claim_id(stream1), data=b'news', bid='1.0') await self.stream_update(self.get_claim_id(stream1), data=b'news', bid='1.0')
await self.support_create(self.get_claim_id(stream1), '2.0') await self.support_create(self.get_claim_id(stream1), '2.0')
self.assertEqual(await account_balance(reserved_subtotals=True), { expected = {
'total': '9.977534', 'total': '9.977534',
'available': '6.977534', 'available': '6.977534',
'reserved': '3.0', 'reserved': '3.0',
'reserved_subtotals': {'claims': '1.0', 'supports': '2.0', 'tips': '0.0'} 'reserved_subtotals': {'claims': '1.0', 'supports': '2.0', 'tips': '0.0'}
}) }
self.assertEqual(await account_balance(reserved_subtotals=True), expected)
self.assertEqual(await wallet_balance(reserved_subtotals=True), expected)
account2 = await self.daemon.jsonrpc_account_create("Tip-er")
address2 = await self.daemon.jsonrpc_address_unused(account2.id) address2 = await self.daemon.jsonrpc_address_unused(account2.id)
# send lbc to someone else # send lbc to someone else
@ -77,6 +85,12 @@ class TransactionCommandsTestCase(CommandTestCase):
'reserved': '3.0', 'reserved': '3.0',
'reserved_subtotals': {'claims': '1.0', 'supports': '2.0', 'tips': '0.0'} 'reserved_subtotals': {'claims': '1.0', 'supports': '2.0', 'tips': '0.0'}
}) })
self.assertEqual(await wallet_balance(reserved_subtotals=True), {
'total': '9.97741',
'available': '6.97741',
'reserved': '3.0',
'reserved_subtotals': {'claims': '1.0', 'supports': '2.0', 'tips': '0.0'}
})
# tip received # tip received
support1 = await self.support_create( support1 = await self.support_create(
@ -88,6 +102,12 @@ class TransactionCommandsTestCase(CommandTestCase):
'reserved': '3.3', 'reserved': '3.3',
'reserved_subtotals': {'claims': '1.0', 'supports': '2.0', 'tips': '0.3'} 'reserved_subtotals': {'claims': '1.0', 'supports': '2.0', 'tips': '0.3'}
}) })
self.assertEqual(await wallet_balance(reserved_subtotals=True), {
'total': '9.977268',
'available': '6.677268',
'reserved': '3.3',
'reserved_subtotals': {'claims': '1.0', 'supports': '2.0', 'tips': '0.3'}
})
# tip claimed # tip claimed
tx = await self.daemon.jsonrpc_support_abandon(txid=support1['txid'], nout=0) tx = await self.daemon.jsonrpc_support_abandon(txid=support1['txid'], nout=0)
@ -98,6 +118,12 @@ class TransactionCommandsTestCase(CommandTestCase):
'reserved': '3.0', 'reserved': '3.0',
'reserved_subtotals': {'claims': '1.0', 'supports': '2.0', 'tips': '0.0'} 'reserved_subtotals': {'claims': '1.0', 'supports': '2.0', 'tips': '0.0'}
}) })
self.assertEqual(await wallet_balance(reserved_subtotals=True), {
'total': '9.977161',
'available': '6.977161',
'reserved': '3.0',
'reserved_subtotals': {'claims': '1.0', 'supports': '2.0', 'tips': '0.0'}
})
stream2 = await self.stream_create( stream2 = await self.stream_create(
'granularity-is-cool', '0.1', account_id=account2.id, funding_account_ids=[account2.id] 'granularity-is-cool', '0.1', account_id=account2.id, funding_account_ids=[account2.id]
@ -105,10 +131,17 @@ class TransactionCommandsTestCase(CommandTestCase):
# tip another claim # tip another claim
await self.support_create( await self.support_create(
self.get_claim_id(stream2), '0.2', tip=True, funding_account_ids=[self.account.id]) self.get_claim_id(stream2), '0.2', tip=True, funding_account_ids=[self.account.id]
)
self.assertEqual(await account_balance(reserved_subtotals=True), { self.assertEqual(await account_balance(reserved_subtotals=True), {
'total': '9.077157', 'total': '9.077157',
'available': '6.077157', 'available': '6.077157',
'reserved': '3.0', 'reserved': '3.0',
'reserved_subtotals': {'claims': '1.0', 'supports': '2.0', 'tips': '0.0'} 'reserved_subtotals': {'claims': '1.0', 'supports': '2.0', 'tips': '0.0'}
}) })
self.assertEqual(await wallet_balance(reserved_subtotals=True), {
'total': '9.938908',
'available': '6.638908',
'reserved': '3.3',
'reserved_subtotals': {'claims': '1.1', 'supports': '2.0', 'tips': '0.2'}
})