cic-internal-integration/apps/cic-ussd/cic_ussd/account/balance.py

145 lines
5.3 KiB
Python
Raw Permalink Normal View History

2021-08-06 18:29:01 +02:00
# standard imports
2021-09-17 13:15:43 +02:00
2021-08-06 18:29:01 +02:00
import json
import logging
2021-11-29 16:04:50 +01:00
from typing import Union, Optional
2021-08-06 18:29:01 +02:00
# third-party imports
from cic_eth.api import Api
2021-09-17 13:15:43 +02:00
from cic_eth_aux.erc20_demurrage_token.api import Api as DemurrageApi
from cic_types.condiments import MetadataPointer
2021-08-06 18:29:01 +02:00
# local imports
from cic_ussd.account.transaction import from_wei
from cic_ussd.cache import cache_data_key, get_cached_data
from cic_ussd.error import CachedDataNotFoundError
2021-11-29 16:04:50 +01:00
logg = logging.getLogger(__file__)
2021-08-06 18:29:01 +02:00
def get_balances(address: str,
chain_str: str,
token_symbol: str,
asynchronous: bool = False,
callback_param: any = None,
callback_queue='cic-ussd',
2021-08-25 12:33:35 +02:00
callback_task='cic_ussd.tasks.callback_handler.balances_callback') -> Optional[list]:
2021-08-06 18:29:01 +02:00
"""This function queries cic-eth for an account's balances, It provides a means to receive the balance either
asynchronously or synchronously.. It returns a dictionary containing the network, outgoing and incoming balances.
:param address: Ethereum address of an account.
:type address: str, 0x-hex
:param chain_str: The chain name and network id.
:type chain_str: str
:param asynchronous: Boolean value checking whether to return balances asynchronously.
:type asynchronous: bool
:param callback_param: Data to be sent along with the callback containing balance data.
:type callback_param: any
:param callback_queue:
:type callback_queue:
:param callback_task: A celery task path to which callback data should be sent.
:type callback_task: str
:param token_symbol: ERC20 token symbol of the account whose balance is being queried.
:type token_symbol: str
:return: A list containing balance data if called synchronously. | None
:rtype: list | None
"""
2021-11-29 16:04:50 +01:00
logg.debug(f'retrieving {token_symbol} balance for address: {address}')
2021-08-06 18:29:01 +02:00
if asynchronous:
cic_eth_api = Api(
chain_str=chain_str,
callback_queue=callback_queue,
callback_task=callback_task,
callback_param=callback_param
)
cic_eth_api.balance(address=address, token_symbol=token_symbol)
else:
cic_eth_api = Api(chain_str=chain_str)
balance_request_task = cic_eth_api.balance(
address=address,
token_symbol=token_symbol)
return balance_request_task.get()
2021-11-29 16:04:50 +01:00
def calculate_available_balance(balances: dict, decimals: int) -> float:
2021-08-06 18:29:01 +02:00
"""This function calculates an account's balance at a specific point in time by computing the difference from the
outgoing balance and the sum of the incoming and network balances.
:param balances: incoming, network and outgoing balances.
:type balances: dict
2021-11-29 16:04:50 +01:00
:param decimals:
:type decimals: int
2021-08-06 18:29:01 +02:00
:return: Token value of the available balance.
:rtype: float
"""
incoming_balance = balances.get('balance_incoming')
outgoing_balance = balances.get('balance_outgoing')
network_balance = balances.get('balance_network')
available_balance = (network_balance + incoming_balance) - outgoing_balance
2021-11-29 16:04:50 +01:00
return from_wei(decimals=decimals, value=available_balance)
2021-08-06 18:29:01 +02:00
2021-09-17 13:15:43 +02:00
def get_adjusted_balance(balance: int, chain_str: str, timestamp: int, token_symbol: str):
"""
:param balance:
:type balance:
:param chain_str:
:type chain_str:
:param timestamp:
:type timestamp:
:param token_symbol:
:type token_symbol:
:return:
:rtype:
"""
logg.debug(f'retrieving adjusted balance on chain: {chain_str}')
demurrage_api = DemurrageApi(chain_str=chain_str)
return demurrage_api.get_adjusted_balance(token_symbol, balance, timestamp).result
2021-11-29 16:04:50 +01:00
def get_cached_available_balance(decimals: int, identifier: Union[list, bytes]) -> float:
2021-08-06 18:29:01 +02:00
"""This function attempts to retrieve balance data from the redis cache.
2021-11-29 16:04:50 +01:00
:param decimals:
:type decimals: int
:param identifier: An identifier needed to create a unique pointer to a balances resource.
:type identifier: bytes | list
2021-08-06 18:29:01 +02:00
:raises CachedDataNotFoundError: No cached balance data could be found.
:return: Operational balance of an account.
:rtype: float
"""
2021-11-29 16:04:50 +01:00
key = cache_data_key(identifier=identifier, salt=MetadataPointer.BALANCES)
2021-08-06 18:29:01 +02:00
cached_balances = get_cached_data(key=key)
if cached_balances:
2021-11-29 16:04:50 +01:00
return calculate_available_balance(balances=json.loads(cached_balances), decimals=decimals)
2021-08-06 18:29:01 +02:00
else:
2021-11-29 16:04:50 +01:00
raise CachedDataNotFoundError(f'No cached available balance at {key}')
2021-09-17 13:15:43 +02:00
2021-11-29 16:04:50 +01:00
def get_cached_adjusted_balance(identifier: Union[list, bytes]):
2021-09-17 13:15:43 +02:00
"""
:param identifier:
:type identifier:
:return:
:rtype:
"""
key = cache_data_key(identifier, MetadataPointer.BALANCES_ADJUSTED)
2021-09-17 13:15:43 +02:00
return get_cached_data(key)
2021-11-29 16:04:50 +01:00
def get_account_tokens_balance(blockchain_address: str, chain_str: str, token_symbols_list: list):
"""
:param blockchain_address:
:type blockchain_address:
:param chain_str:
:type chain_str:
:param token_symbols_list:
:type token_symbols_list:
:return:
:rtype:
"""
for token_symbol in token_symbols_list:
get_balances(address=blockchain_address,
chain_str=chain_str,
token_symbol=token_symbol,
asynchronous=True,
callback_param=f'{blockchain_address},{token_symbol}')