forked from LBRYCommunity/lbry-sdk
added wallet balance command
This commit is contained in:
parent
fea7275148
commit
e2b92c99ef
5 changed files with 105 additions and 19 deletions
|
@ -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(
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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'}
|
||||||
|
})
|
||||||
|
|
Loading…
Reference in a new issue