def _handle_pooltogether(normalized_balance: FVal, token_name: str) -> Optional[DefiBalance]: """Special handling for pooltogether https://github.com/rotki/rotki/issues/1429 """ if 'DAI' in token_name: dai_price = Inquirer.find_usd_price(A_DAI) return DefiBalance( token_address=string_to_ethereum_address( '0x49d716DFe60b37379010A75329ae09428f17118d'), token_name='Pool Together DAI token', token_symbol='plDAI', balance=Balance( amount=normalized_balance, usd_value=normalized_balance * dai_price, ), ) if 'USDC' in token_name: usdc_price = Inquirer.find_usd_price(A_USDC) return DefiBalance( token_address=string_to_ethereum_address( '0xBD87447F48ad729C5c4b8bcb503e1395F62e8B98'), token_name='Pool Together USDC token', token_symbol='plUSDC', balance=Balance( amount=normalized_balance, usd_value=normalized_balance * usdc_price, ), ) # else return None
def deserialize_from_db( cls, event_tuple: LiquidityPoolEventDBTuple, ) -> 'LiquidityPoolEvent': """Turns a tuple read from DB into an appropriate LiquidityPoolEvent. May raise a DeserializationError if something is wrong with the DB data Event_tuple index - Schema columns ---------------------------------- 0 - tx_hash 1 - log_index 2 - address 3 - timestamp 4 - type 5 - pool_address 6 - token0_identifier 7 - token1_identifier 8 - amount0 9 - amount1 10 - usd_price 11 - lp_amount """ db_event_type = event_tuple[4] if db_event_type not in {str(event_type) for event_type in EventType}: raise DeserializationError( f'Failed to deserialize event type. Unknown event: {db_event_type}.', ) if db_event_type == str(EventType.MINT): event_type = EventType.MINT elif db_event_type == str(EventType.BURN): event_type = EventType.BURN else: raise ValueError(f'Unexpected event type case: {db_event_type}.') token0 = deserialize_ethereum_token_from_db(identifier=event_tuple[6]) token1 = deserialize_ethereum_token_from_db(identifier=event_tuple[7]) return cls( tx_hash=event_tuple[0], log_index=event_tuple[1], address=string_to_ethereum_address(event_tuple[2]), timestamp=deserialize_timestamp(event_tuple[3]), event_type=event_type, pool_address=string_to_ethereum_address(event_tuple[5]), token0=token0, token1=token1, amount0=deserialize_asset_amount(event_tuple[8]), amount1=deserialize_asset_amount(event_tuple[9]), usd_price=deserialize_price(event_tuple[10]), lp_amount=deserialize_asset_amount(event_tuple[11]), )
def deserialize_from_db( cls, event_tuple: BalancerEventDBTuple, ) -> 'BalancerEvent': """May raise DeserializationError Event_tuple index - Schema columns ---------------------------------- 0 - tx_hash 1 - log_index 2 - address 3 - timestamp 4 - type 5 - pool_address 6 - lp_amount 7 - usd_value 8 - amount0 9 - amount1 10 - amount2 11 - amount3 12 - amount4 13 - amount5 14 - amount6 15 - amount7 """ event_tuple_type = event_tuple[4] try: event_type = getattr(BalancerBPTEventType, event_tuple_type.upper()) except AttributeError as e: raise DeserializationError( f'Unexpected event type: {event_tuple_type}.') from e amounts: List[AssetAmount] = [ deserialize_asset_amount(item) for item in event_tuple[8:16] if item is not None ] return cls( tx_hash=event_tuple[0], log_index=event_tuple[1], address=string_to_ethereum_address(event_tuple[2]), timestamp=deserialize_timestamp(event_tuple[3]), event_type=event_type, pool_address=string_to_ethereum_address(event_tuple[5]), lp_balance=Balance( amount=deserialize_asset_amount(event_tuple[6]), usd_value=deserialize_price(event_tuple[7]), ), amounts=amounts, )
def query_tokens_for_addresses( self, addresses: List[ChecksumEthAddress], force_detection: bool, ) -> TokensReturn: """Queries/detects token balances for a list of addresses If an address's tokens were recently autodetected they are not detected again but the balances are simply queried. Unless force_detection is True. Returns the token balances of each address and the usd prices of the tokens """ log.debug( 'Querying/detecting token balances for all addresses', force_detection=force_detection, ) all_tokens = GlobalDBHandler().get_ethereum_tokens(exceptions=[ # Ignore the veCRV balance in token query. It's already detected by # defi SDK as part of locked CRV in Vote Escrowed CRV. Which is the right way # to approach it as there is no way to assign a price to 1 veCRV. It # can be 1 CRV locked for 4 years or 4 CRV locked for 1 year etc. string_to_ethereum_address( '0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2'), ]) # With etherscan with chunks > 120, we get request uri too large # so the limitation is not in the gas, but in the request uri length etherscan_chunks = list( get_chunks(all_tokens, n=ETHERSCAN_MAX_TOKEN_CHUNK_LENGTH)) other_chunks = list( get_chunks(all_tokens, n=OTHER_MAX_TOKEN_CHUNK_LENGTH)) now = ts_now() token_usd_price: Dict[EthereumToken, Price] = {} result = {} for address in addresses: saved_list = self.db.get_tokens_for_address_if_time( address=address, current_time=now) if force_detection or saved_list is None: balances = self.detect_tokens_for_address( address=address, token_usd_price=token_usd_price, etherscan_chunks=etherscan_chunks, other_chunks=other_chunks, ) else: if len(saved_list) == 0: continue # Do not query if we know the address has no tokens balances = defaultdict(FVal) self._get_tokens_balance_and_price( address=address, tokens=[x.to_custom_ethereum_token() for x in saved_list], balances=balances, token_usd_price=token_usd_price, call_order=None, # use defaults ) result[address] = balances return result, token_usd_price
def deserialize_from_db( cls, event_tuple: BalancerEventDBTuple, ) -> 'BalancerEvent': """May raise DeserializationError Event_tuple index - Schema columns ---------------------------------- 0 - tx_hash 1 - log_index 2 - address 3 - timestamp 4 - type 5 - pool_address_token 6 - lp_amount 7 - usd_value 8 - amount0 9 - amount1 10 - amount2 11 - amount3 12 - amount4 13 - amount5 14 - amount6 15 - amount7 """ event_tuple_type = event_tuple[4] try: event_type = getattr(BalancerBPTEventType, event_tuple_type.upper()) except AttributeError as e: raise DeserializationError( f'Unexpected event type: {event_tuple_type}.') from e pool_address_token = EthereumToken.from_identifier( event_tuple[5], form_with_incomplete_data= True, # since some may not have decimals input correctly ) if pool_address_token is None: raise DeserializationError( f'Balancer event pool token: {event_tuple[5]} not found in the DB.', ) amounts: List[AssetAmount] = [ deserialize_asset_amount(item) for item in event_tuple[8:16] if item is not None ] return cls( tx_hash=event_tuple[0], log_index=event_tuple[1], address=string_to_ethereum_address(event_tuple[2]), timestamp=deserialize_timestamp(event_tuple[3]), event_type=event_type, pool_address_token=pool_address_token, lp_balance=Balance( amount=deserialize_asset_amount(event_tuple[6]), usd_value=deserialize_price(event_tuple[7]), ), amounts=amounts, )
def get_all_asset_data( mapping: bool ) -> Union[List[AssetData], Dict[str, Dict[str, Any]]]: """Return all asset data from the DB TODO: This can be improved. Too many sql queries. If mapping is True, return them as a Dict of identifier to data If mapping is False, return them as a List of AssetData """ result: Union[List[AssetData], Dict[str, Dict[str, Any]]] if mapping: result = {} else: result = [] cursor = GlobalDBHandler()._conn.cursor() querystr = """ SELECT A.identifier, A.type, B.address, B.decimals, A.name, A.symbol, A.started, null, A.swapped_for, A.coingecko, A.cryptocompare, B.protocol from assets as A LEFT OUTER JOIN ethereum_tokens as B ON B.address = A.details_reference WHERE A.type=? UNION ALL SELECT A.identifier, A.type, null, null, A.name, A.symbol, A.started, B.forked, A.swapped_for, A.coingecko, A.cryptocompare, null from assets as A LEFT OUTER JOIN common_asset_details as B ON B.asset_id = A.identifier WHERE A.type!=?; """ # noqa: E501 eth_token_type = AssetType.ETHEREUM_TOKEN.serialize_for_db() # pylint: disable=no-member query = cursor.execute(querystr, (eth_token_type, eth_token_type)) for entry in query: asset_type = AssetType.deserialize_from_db(entry[1]) ethereum_address: Optional[ChecksumEthAddress] if asset_type == AssetType.ETHEREUM_TOKEN: ethereum_address = string_to_ethereum_address(entry[2]) else: ethereum_address = None data = AssetData( identifier=entry[0], asset_type=asset_type, ethereum_address=ethereum_address, decimals=entry[3], name=entry[4], symbol=entry[5], started=entry[6], forked=entry[7], swapped_for=entry[8], coingecko=entry[9], cryptocompare=entry[10], protocol=entry[11], ) if mapping: result[entry[0]] = data.serialize() # type: ignore else: result.append(data) # type: ignore return result
def deserialize_from_db( cls, event_tuple: LiquidityPoolEventDBTuple, ) -> 'LiquidityPoolEvent': """Turns a tuple read from DB into an appropriate LiquidityPoolEvent. May raise a DeserializationError if something is wrong with the DB data Event_tuple index - Schema columns ---------------------------------- 0 - tx_hash 1 - log_index 2 - address 3 - timestamp 4 - type 5 - pool_address 6 - token0_identifier 7 - token1_identifier 8 - amount0 9 - amount1 10 - usd_price 11 - lp_amount """ event_type = EventType.deserialize_from_db(event_tuple[4]) token0 = deserialize_ethereum_token_from_db(identifier=event_tuple[6]) token1 = deserialize_ethereum_token_from_db(identifier=event_tuple[7]) return cls( tx_hash=event_tuple[0], log_index=event_tuple[1], address=string_to_ethereum_address(event_tuple[2]), timestamp=deserialize_timestamp(event_tuple[3]), event_type=event_type, pool_address=string_to_ethereum_address(event_tuple[5]), token0=token0, token1=token1, amount0=deserialize_asset_amount(event_tuple[8]), amount1=deserialize_asset_amount(event_tuple[9]), usd_price=deserialize_price(event_tuple[10]), lp_amount=deserialize_asset_amount(event_tuple[11]), )
def get_assets_with_symbol( symbol: str, asset_type: Optional[AssetType] = None ) -> List[AssetData]: # noqa: E501 """Find all asset entries that have the given symbol""" connection = GlobalDBHandler()._conn cursor = connection.cursor() query_tuples: Union[Tuple[str, str, str, str], Tuple[str, str, str, str, str]] eth_token_type = AssetType.ETHEREUM_TOKEN.serialize_for_db() # pylint: disable=no-member if asset_type is not None: asset_type_check = ' AND A.type=?' query_tuples = (symbol, eth_token_type, symbol, eth_token_type, asset_type.serialize_for_db()) # noqa: E501 else: asset_type_check = '' query_tuples = (symbol, eth_token_type, symbol, eth_token_type) querystr = f""" SELECT A.identifier, A.type, B.address, B.decimals, A.name, A.symbol, A.started, null, A.swapped_for, A.coingecko, A.cryptocompare, B.protocol from assets as A LEFT OUTER JOIN ethereum_tokens as B ON B.address = A.details_reference WHERE A.symbol=? COLLATE NOCASE AND A.type=? UNION ALL SELECT A.identifier, A.type, null, null, A.name, A.symbol, A.started, B.forked, A.swapped_for, A.coingecko, A.cryptocompare, null from assets as A LEFT OUTER JOIN common_asset_details as B ON B.asset_id = A.identifier WHERE A.symbol=? COLLATE NOCASE AND A.type!=?{asset_type_check}; """ # noqa: E501 query = cursor.execute(querystr, query_tuples) assets = [] for entry in query: asset_type = AssetType.deserialize_from_db(entry[1]) ethereum_address: Optional[ChecksumEthAddress] if asset_type == AssetType.ETHEREUM_TOKEN: ethereum_address = string_to_ethereum_address(entry[2]) else: ethereum_address = None assets.append( AssetData( identifier=entry[0], asset_type=asset_type, ethereum_address=ethereum_address, decimals=entry[3], name=entry[4], symbol=entry[5], started=entry[6], forked=entry[7], swapped_for=entry[8], coingecko=entry[9], cryptocompare=entry[10], protocol=entry[11], )) return assets
def have_archive(self, requery: bool = False) -> bool: """Checks to see if our own connected node is an archive node If requery is True it always queries the node. Otherwise it remembers last query. """ if self.queried_archive_connection and requery is False: return self.archive_connection balance = self.get_historical_eth_balance( address=string_to_ethereum_address( '0x50532e4Be195D1dE0c2E6DfA46D9ec0a4Fee6861'), block_number=87042, ) self.archive_connection = balance is not None and balance == FVal( '5.1063307') self.queried_archive_connection = True return self.archive_connection
def deserialize_unknown_ethereum_token_from_db( ethereum_address: str, symbol: str, name: Optional[str], decimals: Optional[int], ) -> UnknownEthereumToken: """Takes at least an ethereum address and a symbol, and returns an <UnknownEthereumToken> """ try: unknown_ethereum_token = UnknownEthereumToken( ethereum_address=string_to_ethereum_address(ethereum_address), symbol=symbol, name=name, decimals=decimals, ) except Exception as e: raise DeserializationError( f'Failed deserializing an unknown ethereum token with ' f'address {ethereum_address}, symbol {symbol}, name {name}, ' f'decimals {decimals}.', ) from e return unknown_ethereum_token
import random import pytest import requests from rotkehlchen.chain.ethereum.typing import string_to_ethereum_address from rotkehlchen.constants.assets import A_ETH, A_LQTY, A_LUSD from rotkehlchen.fval import FVal from rotkehlchen.tests.utils.api import ( api_url_for, assert_ok_async_response, assert_proper_response_with_result, wait_for_async_task_with_result, ) LQTY_ADDR = string_to_ethereum_address( '0x063c26fF1592688B73d8e2A18BA4C23654e2792E') LQTY_STAKING = string_to_ethereum_address( '0x018565899A88f75E6edfEA0639183adF8c205641') LQTY_PROXY = string_to_ethereum_address( '0x9476832d4687c14b2c1a04E2ee4693162a7340B6') ADDR_WITHOUT_TROVE = string_to_ethereum_address( '0xA0446D8804611944F1B527eCD37d7dcbE442caba') liquity_mocked_historical_prices = { A_ETH: { 'USD': { 1627818194: FVal('3000'), 1627818617: FVal('3000'), 1627827057: FVal('3500'), 1641529258: FVal('3395'), },
ValidatorPerformance, string_to_ethereum_address, ) from rotkehlchen.constants.misc import ZERO from rotkehlchen.fval import FVal from rotkehlchen.serialization.serialize import process_result_list from rotkehlchen.tests.utils.ethereum import ( ETHEREUM_TEST_PARAMETERS, wait_until_all_nodes_connected, ) from rotkehlchen.tests.utils.factories import make_ethereum_address from rotkehlchen.tests.utils.mock import MockResponse from rotkehlchen.typing import Timestamp from rotkehlchen.user_messages import MessagesAggregator ADDR1 = string_to_ethereum_address( '0xfeF0E7635281eF8E3B705e9C5B86e1d3B0eAb397') ADDR2 = string_to_ethereum_address( '0x00F8a0D8EE1c21151BCcB416bCa1C152f9952D19') ADDR3 = string_to_ethereum_address( '0x3266F3546a1e5Dc6A15588f3324741A0E20a3B6c') # List of ADDR1, ADDR2 and ADDR3 deposit events from 1604506685 to 1605044577 # sorted by (timestamp, log_index). EXPECTED_DEPOSITS = [ Eth2Deposit( from_address=ADDR1, pubkey= '0xb016e31f633a21fbe42a015152399361184f1e2c0803d89823c224994af74a561c4ad8cfc94b18781d589d03e952cd5b', # noqa: E501 withdrawal_credentials= '0x004c7691c2085648f394ffaef851f3b1d51b95f7263114bc923fc5338f5fc499', # noqa: E501 value=Balance(FVal(32), FVal(64)),
def test_get_asset_with_symbol(globaldb): # both categories of assets asset_data = globaldb.get_assets_with_symbol('KEY') bihukey_address = string_to_ethereum_address( '0x4Cd988AfBad37289BAAf53C13e98E2BD46aAEa8c') aave_address = string_to_ethereum_address( '0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9') renbtc_address = string_to_ethereum_address( '0xEB4C2781e4ebA804CE9a9803C67d0893436bB27D') assert asset_data == [ selfkey_asset_data, AssetData( identifier=ethaddress_to_identifier(bihukey_address), name='Bihu KEY', symbol='KEY', asset_type=AssetType.ETHEREUM_TOKEN, started=1507822985, forked=None, swapped_for=None, ethereum_address=bihukey_address, decimals=18, cryptocompare='BIHU', coingecko='key', protocol=None, ), AssetData( identifier='KEY-3', name='KeyCoin', symbol='KEY', asset_type=AssetType.OWN_CHAIN, started=1405382400, forked=None, swapped_for=None, ethereum_address=None, decimals=None, cryptocompare='KEYC', coingecko='', protocol=None, ) ] # only non-ethereum token assert globaldb.get_assets_with_symbol('BIDR') == [bidr_asset_data] # only ethereum token assert globaldb.get_assets_with_symbol('AAVE') == [ AssetData( identifier=ethaddress_to_identifier(aave_address), name='Aave Token', symbol='AAVE', asset_type=AssetType.ETHEREUM_TOKEN, started=1600970788, forked=None, swapped_for=None, ethereum_address=aave_address, decimals=18, cryptocompare=None, coingecko='aave', protocol=None, ) ] # finally non existing asset assert globaldb.get_assets_with_symbol('DASDSADSDSDSAD') == [] # also check that symbol comparison is case insensitive for many arg combinations expected_renbtc = [ AssetData( identifier=ethaddress_to_identifier(renbtc_address), name='renBTC', symbol='renBTC', asset_type=AssetType.ETHEREUM_TOKEN, started=1585090944, forked=None, swapped_for=None, ethereum_address=renbtc_address, decimals=8, cryptocompare=None, coingecko='renbtc', protocol=None, ) ] for x in itertools.product(('ReNbTc', 'renbtc', 'RENBTC', 'rEnBTc'), (None, AssetType.ETHEREUM_TOKEN)): # noqa: E501 assert globaldb.get_assets_with_symbol(*x) == expected_renbtc
from rotkehlchen.assets.utils import symbol_to_asset_or_token from rotkehlchen.chain.ethereum.typing import string_to_ethereum_address from rotkehlchen.constants.assets import A_BAT, A_CRV, A_DAI, A_PICKLE from rotkehlchen.constants.misc import NFT_DIRECTIVE from rotkehlchen.constants.resolver import ethaddress_to_identifier from rotkehlchen.errors import InputError from rotkehlchen.exchanges.data_structures import Trade from rotkehlchen.globaldb.handler import GLOBAL_DB_VERSION, GlobalDBHandler from rotkehlchen.history.typing import HistoricalPriceOracle from rotkehlchen.serialization.deserialize import deserialize_asset_amount from rotkehlchen.tests.fixtures.globaldb import create_globaldb from rotkehlchen.tests.utils.factories import make_ethereum_address from rotkehlchen.tests.utils.globaldb import INITIAL_TOKENS from rotkehlchen.typing import Location, Price, Timestamp, TradeType selfkey_address = string_to_ethereum_address( '0x4CC19356f2D37338b9802aa8E8fc58B0373296E7') selfkey_id = ethaddress_to_identifier(selfkey_address) selfkey_asset_data = AssetData( identifier=selfkey_id, name='Selfkey', symbol='KEY', asset_type=AssetType.ETHEREUM_TOKEN, started=Timestamp(1508803200), forked=None, swapped_for=None, ethereum_address=selfkey_address, decimals=18, cryptocompare=None, coingecko='selfkey', protocol=None, )
from rotkehlchen.serialization.deserialize import ( deserialize_asset_amount, deserialize_ethereum_address, deserialize_timestamp, ) from .typing import AdexEventDBTuple, AdexEventType, Bond, ChannelWithdraw, Unbond, UnbondRequest # Constants from the AdExNetwork repo IDENTITY_FACTORY_ADDR = '0x9fe0d438E3c29C7CFF949aD8e8dA9403A531cC1A' IDENTITY_PROXY_INIT_CODE = ( '0x608060405234801561001057600080fd5b5060026000803073ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600260008073' # noqa: E501 '{signer_address}' '73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908360ff1602179055506000734470bb87d77b963a013db939be332f927f2b992e9050600073ade00c28244d5ce17d72e40330b1c318cd12b7c3905060008273ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016101429190610501565b60206040518083038186803b15801561015a57600080fd5b505afa15801561016e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610192919061045a565b90506000811115610276578273ffffffffffffffffffffffffffffffffffffffff1663095ea7b383836040518363ffffffff1660e01b81526004016101d892919061051c565b600060405180830381600087803b1580156101f257600080fd5b505af1158015610206573d6000803e3d6000fd5b505050508173ffffffffffffffffffffffffffffffffffffffff166394b918de826040518263ffffffff1660e01b81526004016102439190610560565b600060405180830381600087803b15801561025d57600080fd5b505af1158015610271573d6000803e3d6000fd5b505050505b60008273ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016102b19190610501565b60206040518083038186803b1580156102c957600080fd5b505afa1580156102dd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610301919061045a565b9050600081111561043c576000734846c6837ec670bbd1f5b485471c8f64ecb9c53490508373ffffffffffffffffffffffffffffffffffffffff1663095ea7b382846040518363ffffffff1660e01b815260040161036092919061051c565b600060405180830381600087803b15801561037a57600080fd5b505af115801561038e573d6000803e3d6000fd5b505050508073ffffffffffffffffffffffffffffffffffffffff1663b4dca72460405180606001604052808581526020017f2ce0c96383fb229d9776f33846e983a956a7d95844fac57b180ed0071d93bb2860001b8152602001428152506040518263ffffffff1660e01b81526004016104089190610545565b600060405180830381600087803b15801561042257600080fd5b505af1158015610436573d6000803e3d6000fd5b50505050505b505050506105d8565b600081519050610454816105c1565b92915050565b60006020828403121561046c57600080fd5b600061047a84828501610445565b91505092915050565b61048c8161057b565b82525050565b61049b8161058d565b82525050565b6060820160008201516104b760008501826104e3565b5060208201516104ca6020850182610492565b5060408201516104dd60408501826104e3565b50505050565b6104ec816105b7565b82525050565b6104fb816105b7565b82525050565b60006020820190506105166000830184610483565b92915050565b60006040820190506105316000830185610483565b61053e60208301846104f2565b9392505050565b600060608201905061055a60008301846104a1565b92915050565b600060208201905061057560008301846104f2565b92915050565b600061058682610597565b9050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b6105ca816105b7565b81146105d557600080fd5b50565b6101b7806105e76000396000f3fe608060405234801561001057600080fd5b506004361061002f5760003560e01c8063c066a5b11461007357610030565b5b60007396e3cb4b4632ed45363ff2c9f0fbec9b583d9d3a90503660008037600080366000846127105a03f43d6000803e806000811461006e573d6000f35b3d6000fd5b61008d600480360381019061008891906100d8565b6100a3565b60405161009a9190610110565b60405180910390f35b60006020528060005260406000206000915054906101000a900460ff1681565b6000813590506100d28161016a565b92915050565b6000602082840312156100ea57600080fd5b60006100f8848285016100c3565b91505092915050565b61010a8161015d565b82525050565b60006020820190506101256000830184610101565b92915050565b60006101368261013d565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600060ff82169050919050565b6101738161012b565b811461017e57600080fd5b5056fea26469706673582212200e40aa3025d54e828fb973089b64ce06688fedcd71b98ae68521a0217652c59564736f6c634300060c0033' # noqa: E501 ) STAKING_ADDR = string_to_ethereum_address( '0x4846C6837ec670Bbd1f5b485471c8f64ECB9c534') CREATE2_SALT = f'0x{bytearray(32).hex()}' ADX_AMOUNT_MANTISSA = FVal(10**18) ADEX_EVENTS_PREFIX = 'adex_events' # Defines the expected order of the events given the same timestamp and sorting # in ascending mode EVENT_TYPE_ORDER_IN_ASC = { Bond: 3, ChannelWithdraw: 1, Unbond: 2, UnbondRequest: 4, }
def get_balancer_test_addr2_expected_trades(): """In a function since the new(unknown) assets needs to have been loaded in the DB""" A_WCRES = EthereumToken.initialize( # noqa: N806 address=string_to_ethereum_address( '0xa0afAA285Ce85974c3C881256cB7F225e3A1178a'), decimals=18, symbol='wCRES', ) return [ AMMTrade( trade_type=TradeType.BUY, base_asset=A_WETH, quote_asset=A_AAVE, amount=AssetAmount(FVal('1.616934038985744521')), rate=Price(FVal('6.963972908793392530935439799')), trade_index=1, swaps=[ AMMSwap( tx_hash= '0x3c457da9b541ae39a7dc781ab04a03938b98b5649512aec2a2d32635c9bbf589', # noqa: E501 log_index=24, address=string_to_ethereum_address( '0x029f388aC4D5C8BfF490550ce0853221030E822b' ), # noqa: E501 from_address=string_to_ethereum_address( '0x0000000000007F150Bd6f54c40A34d7C3d5e9f56' ), # noqa: E501 to_address=string_to_ethereum_address( '0x7c90a3cd7Ec80dd2F633ed562480AbbEEd3bE546' ), # noqa: E501 timestamp=Timestamp(1607008178), location=Location.BALANCER, token0=A_AAVE, token1=A_WETH, amount0_in=AssetAmount(FVal('11.260284842802604032')), amount1_in=AssetAmount(ZERO), amount0_out=AssetAmount(ZERO), amount1_out=AssetAmount(FVal('1.616934038985744521')), ), ], ), AMMTrade( trade_type=TradeType.BUY, base_asset=A_AAVE, quote_asset=A_WETH, amount=AssetAmount(FVal('11.260286362820602094')), rate=Price(FVal('0.1416068599966922676173010716')), trade_index=0, swaps=[ AMMSwap( tx_hash= '0x3c457da9b541ae39a7dc781ab04a03938b98b5649512aec2a2d32635c9bbf589', # noqa: E501 log_index=18, address=string_to_ethereum_address( '0x029f388aC4D5C8BfF490550ce0853221030E822b' ), # noqa: E501 from_address=string_to_ethereum_address( '0x0000000000007F150Bd6f54c40A34d7C3d5e9f56' ), # noqa: E501 to_address=string_to_ethereum_address( '0x70985E557aE0CD6dC88189a532e54FbC61927BAd' ), # noqa: E501 timestamp=Timestamp(1607008178), location=Location.BALANCER, token0=A_WETH, token1=A_AAVE, amount0_in=AssetAmount(FVal('1.594533794502600192')), amount1_in=AssetAmount(ZERO), amount0_out=AssetAmount(ZERO), amount1_out=AssetAmount(FVal('11.260286362820602094')), ), ], ), AMMTrade( trade_type=TradeType.BUY, base_asset=A_WETH, quote_asset=A_SYN, amount=AssetAmount(FVal('1.352902561458047718')), rate=Price(FVal('724.4303350385182691258363763')), trade_index=0, swaps=[ AMMSwap( tx_hash= '0x5e235216cb03e4eb234014f5ccf3efbfddd40c4576424e2a8204f1d12b96ed35', # noqa: E501 log_index=143, address=string_to_ethereum_address( '0x029f388aC4D5C8BfF490550ce0853221030E822b' ), # noqa: E501 from_address=string_to_ethereum_address( '0x0000000000007F150Bd6f54c40A34d7C3d5e9f56' ), # noqa: E501 to_address=string_to_ethereum_address( '0x8982E9bBf7AC6A49c434aD81D2fF8e16895318e5' ), # noqa: E501 timestamp=Timestamp(1607008218), location=Location.BALANCER, token0=A_SYN, token1=A_WETH, amount0_in=AssetAmount(FVal('980.08365587152306176')), amount1_in=AssetAmount(ZERO), amount0_out=AssetAmount(ZERO), amount1_out=AssetAmount(FVal('1.352902561458047718')), ), ], ), AMMTrade( trade_type=TradeType.BUY, base_asset=A_WETH, quote_asset=A_WCRES, amount=AssetAmount(FVal('0.205709519074945018')), rate=Price(FVal('232.7409943164679514496089589')), trade_index=0, swaps=[ AMMSwap( tx_hash= '0xf54be824b4619777f1db0e3da91b0cd52f6dba730c95a75644e2b085e6ab9824', # noqa: E501 log_index=300, address=string_to_ethereum_address( '0x029f388aC4D5C8BfF490550ce0853221030E822b' ), # noqa: E501 from_address=string_to_ethereum_address( '0x0000000000007F150Bd6f54c40A34d7C3d5e9f56' ), # noqa: E501 to_address=string_to_ethereum_address( '0x10996eC4f3E7A1b314EbD966Fa8b1ad0fE0f8307' ), # noqa: E501 timestamp=Timestamp(1607009877), location=Location.BALANCER, token0=A_WCRES, token1=A_WETH, amount0_in=AssetAmount(FVal('47.87703800986513408')), amount1_in=AssetAmount(ZERO), amount0_out=AssetAmount(ZERO), amount1_out=AssetAmount(FVal('0.205709519074945018')), ), ], ), AMMTrade( trade_type=TradeType.BUY, base_asset=A_API3, quote_asset=A_WETH, amount=AssetAmount(FVal('295.881648100500428692')), rate=Price(FVal('0.003346787723157288562491614498')), trade_index=0, swaps=[ AMMSwap( tx_hash= '0xfed4e15051e3ce4dc0d2816f719701e5920e40bf41614b5feaa3c5a6a0186c03', # noqa: E501 log_index=22, address=string_to_ethereum_address( '0x029f388aC4D5C8BfF490550ce0853221030E822b' ), # noqa: E501 from_address=string_to_ethereum_address( '0x0000000000007F150Bd6f54c40A34d7C3d5e9f56' ), # noqa: E501 to_address=string_to_ethereum_address( '0x997c0fc9578a8194EFDdE2E0cD7aa6A69cFCD7c1' ), # noqa: E501 timestamp=Timestamp(1607010888), location=Location.BALANCER, token0=A_WETH, token1=A_API3, amount0_in=AssetAmount(FVal('0.990253067370299904')), amount1_in=AssetAmount(ZERO), amount0_out=AssetAmount(ZERO), amount1_out=AssetAmount(FVal('295.881648100500428692')), ), ], ), AMMTrade( trade_type=TradeType.BUY, base_asset=A_WETH, quote_asset=A_MFT, amount=AssetAmount(FVal('0.686544199299304057')), rate=Price(FVal('243775.0324093115004367119900')), trade_index=0, swaps=[ AMMSwap( tx_hash= '0xf0147c4b81098676c08ae20ae5bf8f8b60d0ad79eec484f3f93ac6ab49a3c51c', # noqa: E501 log_index=97, address=string_to_ethereum_address( '0x029f388aC4D5C8BfF490550ce0853221030E822b' ), # noqa: E501 from_address=string_to_ethereum_address( '0x0000000000007F150Bd6f54c40A34d7C3d5e9f56' ), # noqa: E501 to_address=string_to_ethereum_address( '0x2Eb6CfbFFC8785Cd0D9f2d233d0a617bF4269eeF' ), # noqa: E501 timestamp=Timestamp(1607015059), location=Location.BALANCER, token0=A_MFT, token1=A_WETH, amount0_in=AssetAmount(FVal('167362.334434612660404224')), amount1_in=AssetAmount(ZERO), amount0_out=AssetAmount(ZERO), amount1_out=AssetAmount(FVal('0.686544199299304057')), ), ], ), AMMTrade( trade_type=TradeType.BUY, base_asset=A_WETH, quote_asset=A_AAVE, amount=AssetAmount(FVal('3.055412574642681758')), rate=Price(FVal('6.916116208273240607778771150')), trade_index=1, swaps=[ AMMSwap( tx_hash= '0x67c0e9a0fdd002d0b9d1cca0c8e4ca4d30435bbf57bbf0091396275efaea414b', # noqa: E501 log_index=37, address=string_to_ethereum_address( '0x029f388aC4D5C8BfF490550ce0853221030E822b' ), # noqa: E501 from_address=string_to_ethereum_address( '0x0000000000007F150Bd6f54c40A34d7C3d5e9f56' ), # noqa: E501 to_address=string_to_ethereum_address( '0x0E552307659E70bF61f918f96AA880Cdec40d7E2' ), # noqa: E501 timestamp=Timestamp(1607015339), location=Location.BALANCER, token0=A_AAVE, token1=A_WETH, amount0_in=AssetAmount(FVal('21.131588430448123904')), amount1_in=AssetAmount(ZERO), amount0_out=AssetAmount(ZERO), amount1_out=AssetAmount(FVal('3.055412574642681758')), ), ], ), AMMTrade( trade_type=TradeType.BUY, base_asset=A_AAVE, quote_asset=A_WETH, amount=AssetAmount(FVal('21.131588567541018817')), rate=Price(FVal('0.1435213742524287826717337545')), trade_index=0, swaps=[ AMMSwap( tx_hash= '0x67c0e9a0fdd002d0b9d1cca0c8e4ca4d30435bbf57bbf0091396275efaea414b', # noqa: E501 log_index=31, address=string_to_ethereum_address( '0x029f388aC4D5C8BfF490550ce0853221030E822b' ), # noqa: E501 from_address=string_to_ethereum_address( '0x0000000000007F150Bd6f54c40A34d7C3d5e9f56' ), # noqa: E501 to_address=string_to_ethereum_address( '0x7c90a3cd7Ec80dd2F633ed562480AbbEEd3bE546' ), # noqa: E501 timestamp=Timestamp(1607015339), location=Location.BALANCER, token0=A_WETH, token1=A_AAVE, amount0_in=AssetAmount(FVal('3.0328346313504')), amount1_in=AssetAmount(ZERO), amount0_out=AssetAmount(ZERO), amount1_out=AssetAmount(FVal('21.131588567541018817')), ), ], ), ]
A_DASH = Asset('DASH') A_WAVES = Asset('WAVES') A_EWT = Asset('EWT') A_XTZ = Asset('XTZ') A_IOTA = Asset('IOTA') A_BSV = Asset('BSV') A_BCH = Asset('BCH') A_CNY = Asset('CNY') A_JPY = Asset('JPY') A_ZEC = Asset('ZEC') A_DOT = Asset('DOT') A_GBP = Asset('GBP') A_CHF = Asset('CHF') A_AUD = Asset('AUD') A_EUR = Asset('EUR') A_KRW = Asset('KRW') A_CAD = Asset('CAD') ETH_ADDRESS1 = string_to_ethereum_address('0x5153493bB1E1642A63A098A65dD3913daBB6AE24') ETH_ADDRESS2 = string_to_ethereum_address('0x4FED1fC4144c223aE3C1553be203cDFcbD38C581') ETH_ADDRESS3 = string_to_ethereum_address('0x267FdC6F9F1C1a783b36126c1A59a9fbEBf42f84') TX_HASH_STR1 = '0x9c81f44c29ff0226f835cd0a8a2f2a7eca6db52a711f8211b566fd15d3e0e8d4' TX_HASH_STR2 = '0x1c81f44c29ff0236f835cd0a8a2f2a7eca6db52a711f8211b566fd15d3e0e899' TX_HASH_STR3 = '0x3c81144c29f60236f735cd0a8a2f2a7e3a6db52a713f8211b562fd15d3e0e192' MOCK_INPUT_DATA = b'123' MOCK_INPUT_DATA_HEX = '0x313233' DEFAULT_TESTS_MAIN_CURRENCY = A_EUR
); INSERT INTO assets(identifier,type, name, symbol, started, swapped_for, coingecko, cryptocompare, details_reference) VALUES("_ceth_0xD178b20c6007572bD1FD01D205cC20D32B4A6015", "C", "Aidus", "AID" , 123, NULL, NULL, "AIDU", "0xD178b20c6007572bD1FD01D205cC20D32B4A6015"); """, AssetData( identifier='_ceth_0xD178b20c6007572bD1FD01D205cC20D32B4A6015', name='Aidus', symbol='AID', asset_type=AssetType.ETHEREUM_TOKEN, started=Timestamp(123), forked=None, swapped_for=None, ethereum_address=string_to_ethereum_address( '0xD178b20c6007572bD1FD01D205cC20D32B4A6015' ), # noqa: E501 decimals=18, cryptocompare='AIDU', coingecko=None, protocol=None, ), None, ), ( """ INSERT INTO assets(identifier,type, name, symbol, started, swapped_for, coingecko, cryptocompare, details_reference) VALUES("121-ada-FADS-as", "F", "A name", "SYMBOL" , NULL, NULL, "", "", "121-ada-FADS-as"); INSERT INTO common_asset_details(asset_id, forked) VALUES(
TEST_ACCOUNTS = [ # For mint/redeem '0x2B888954421b424C5D3D9Ce9bB67c9bD47537d12', # For borrowing/liquidations '0xC440f3C87DC4B6843CABc413916220D4f4FeD117', # For mint/redeem + comp '0xF59D4937BF1305856C3a267bB07791507a3377Ee', # For repay '0x65304d6aff5096472519ca86a6a1fea31cb47Ced', ] EXPECTED_EVENTS = [CompoundEvent( event_type='mint', address=string_to_ethereum_address('0x2B888954421b424C5D3D9Ce9bB67c9bD47537d12'), block_number=9443573, timestamp=Timestamp(1581184577), asset=A_DAI, value=Balance(amount=FVal('2988.4343'), usd_value=FVal('3012.3417744')), to_asset=A_CDAI, to_value=Balance(amount=FVal('148015.6966153'), usd_value=FVal('3012.3417744')), realized_pnl=None, tx_hash='0xacc2e21f911a4e438966694e9ad16747878a15dae52de62a09f1ebabc8b26c8d', log_index=130, ), CompoundEvent( event_type='redeem', address=string_to_ethereum_address('0x2B888954421b424C5D3D9Ce9bB67c9bD47537d12'), block_number=9533397, timestamp=Timestamp(1582378248), asset=A_CDAI,
LiquidityPool, LiquidityPoolAsset, LiquidityPoolEvent, LiquidityPoolEventsBalance, ) from rotkehlchen.chain.ethereum.typing import string_to_ethereum_address from rotkehlchen.constants import ZERO from rotkehlchen.constants.assets import A_USDT, A_WETH from rotkehlchen.fval import FVal from rotkehlchen.tests.utils.constants import A_DOLLAR_BASED from rotkehlchen.typing import AssetAmount, Price, Timestamp # Logic: Get balances # Addresses TEST_ADDRESS_1 = string_to_ethereum_address( '0xfeF0E7635281eF8E3B705e9C5B86e1d3B0eAb397') TEST_ADDRESS_2 = string_to_ethereum_address( '0xcf2B8EeC2A9cE682822b252a1e9B78EedebEFB02') TEST_ADDRESS_3 = string_to_ethereum_address( '0x7777777777777777777777777777777777777777') # Unknown tokens ASSET_SHUF = UnknownEthereumToken( ethereum_address=string_to_ethereum_address( '0x3A9FfF453d50D4Ac52A6890647b823379ba36B9E'), symbol='SHUF', name='Shuffle.Monster V3', decimals=18, ) ASSET_TGX = UnknownEthereumToken( ethereum_address=string_to_ethereum_address(
from rotkehlchen.chain.ethereum.modules.balancer import Balancer from rotkehlchen.chain.ethereum.modules.balancer.utils import get_trades_from_tx_swaps from rotkehlchen.chain.ethereum.trades import AMMSwap, AMMTrade from rotkehlchen.chain.ethereum.typing import string_to_ethereum_address from rotkehlchen.constants.assets import A_REN, A_SNX, A_USDC, A_WETH from rotkehlchen.constants.misc import ZERO from rotkehlchen.fval import FVal from rotkehlchen.tests.api.test_balancer import get_balancer_test_addr2_expected_trades from rotkehlchen.tests.utils.constants import A_AMPL from rotkehlchen.typing import AssetAmount, Location, Price, Timestamp, TradeType TEST_SWAPS_TX_1 = [ AMMSwap( tx_hash='0x1b0d3525964d8e5fbcc0dcdeebcced4bec9017f648e97c3c9761fda1ca6e7b22', log_index=254, address=string_to_ethereum_address('0x8e670b4d6651C4051e65B21AA4a575F3f99b8B83'), from_address=string_to_ethereum_address('0x65003947dC16956AfC4400008606001500940000'), to_address=string_to_ethereum_address('0x7860E28ebFB8Ae052Bfe279c07aC5d94c9cD2937'), timestamp=Timestamp(1614094145), location=Location.BALANCER, token0=A_USDC, token1=A_AMPL, amount0_in=AssetAmount(FVal('12401.224639')), amount1_in=AssetAmount(ZERO), amount0_out=AssetAmount(ZERO), amount1_out=AssetAmount(FVal('14285.153512382')), ), ] TEST_SWAPS_TX_2 = [ AMMSwap( tx_hash='0x1b0d3525964d8e5fbcc0dcdeebcced4bec9017f648e97c3c9761fda1ca6e7b22',
# flake8: noqa import json import os from typing import Any, Dict, List, Optional from rotkehlchen.chain.ethereum.contracts import EthereumContract from rotkehlchen.chain.ethereum.typing import string_to_ethereum_address MAX_BLOCKTIME_CACHE = 250 # 55 mins with 13 secs avg block time ZERO_ADDRESS = string_to_ethereum_address( '0x0000000000000000000000000000000000000000') AAVE_ETH_RESERVE_ADDRESS = string_to_ethereum_address( '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE') class EthereumConstants(): __instance = None contracts: Dict[str, Dict[str, Any]] = {} abi_entries: Dict[str, List[Dict[str, Any]]] = {} def __new__(cls) -> 'EthereumConstants': if EthereumConstants.__instance is not None: return EthereumConstants.__instance # type: ignore EthereumConstants.__instance = object.__new__(cls) dir_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) with open(os.path.join(dir_path, 'data', 'eth_contracts.json'), 'r') as f: contracts = json.loads(f.read())
from rotkehlchen.chain.ethereum.modules.adex.adex import Adex from rotkehlchen.chain.ethereum.modules.adex.typing import TOM_POOL_ID from rotkehlchen.chain.ethereum.typing import string_to_ethereum_address TEST_ADDR = string_to_ethereum_address( '0x494B9728BECA6C03269c38Ed86179757F77Cc0dd') TEST_ADDR_USER_IDENTITY = string_to_ethereum_address( '0xaC29E71ACA2ff1C121673f0FC9d47e7616F692Ae') # noqa: E501 def test_get_user_identity(): """Test our Python port of AdEX `getUserIdentity()` works as expected. AdEX `getUserIdentity()`: https://github.com/AdExNetwork/adex-staking/blob/master/src/helpers/identity.js#L12 """ contract_address = Adex._get_user_identity(address=TEST_ADDR) assert contract_address == TEST_ADDR_USER_IDENTITY def test_get_bond_id(): """Test our Python port of AdEX `getBondId()` calculates the expected bond id using the LogBond event data. Bond tx (origin of `owner`, `amount`, `pool_id` and `nonce`): 0x7944c10032e2a079d3f03ad57a90a93bde468b0baba84121be79790162215855 Unbond tx (claiming and re-staking), its log index 283 contains the expected bond id: 0xc59d65bc6c18e11a3650e8d7ec41a11f58016bbf843376c7f4cb0833402399f1
LiquidityPool, LiquidityPoolAsset, LiquidityPoolEvent, LiquidityPoolEventsBalance, ) from rotkehlchen.chain.ethereum.typing import string_to_ethereum_address from rotkehlchen.constants import ZERO from rotkehlchen.constants.assets import A_USDT, A_WETH from rotkehlchen.fval import FVal from rotkehlchen.tests.utils.constants import A_DOLLAR_BASED from rotkehlchen.typing import AssetAmount, Price, Timestamp # Logic: Get balances # Addresses TEST_ADDRESS_1 = string_to_ethereum_address('0xfeF0E7635281eF8E3B705e9C5B86e1d3B0eAb397') TEST_ADDRESS_2 = string_to_ethereum_address('0xcf2B8EeC2A9cE682822b252a1e9B78EedebEFB02') TEST_ADDRESS_3 = string_to_ethereum_address('0x7777777777777777777777777777777777777777') # Tokens without oracle data (unknown tokens) A_SHL = EthereumToken('0x8542325B72C6D9fC0aD2Ca965A78435413a915A0') A_CAR = EthereumToken('0x4D9e23a3842fE7Eb7682B9725cF6c507C424A41B') A_BTR = EthereumToken('0xcbf15FB8246F679F9Df0135881CB29a3746f734b') # Method: `_get_balances_graph` # 'liquidityPositions' subgraph response data for TEST_ADDRESS_1 LIQUIDITY_POSITION_1 = { 'id': '0x260e069dead76baac587b5141bb606ef8b9bab6c-0xfef0e7635281ef8e3b705e9c5b86e1d3b0eab397', 'liquidityTokenBalance': '52.974048199782328795', 'pair': {
def deserialize_from_db( cls, event_tuple: LiquidityPoolEventDBTuple, ) -> 'LiquidityPoolEvent': """Turns a tuple read from DB into an appropriate LiquidityPoolEvent. May raise a DeserializationError if something is wrong with the DB data Event_tuple index - Schema columns ---------------------------------- 0 - tx_hash 1 - log_index 2 - address 3 - timestamp 4 - type 5 - pool_address 6 - is_token0_unknown 7 - token0_address 8 - token0_symbol 9 - token0_name 10 - token0_decimals 11 - is_token1_unknown 12 - token1_address 13 - token1_symbol 14 - token1_name 15 - token1_decimals 16 - amount0 17 - amount1 18 - usd_price 19 - lp_amount """ db_event_type = event_tuple[4] if db_event_type not in {str(event_type) for event_type in EventType}: raise DeserializationError( f'Failed to deserialize event type. Unknown event: {db_event_type}.', ) if db_event_type == str(EventType.MINT): event_type = EventType.MINT elif db_event_type == str(EventType.BURN): event_type = EventType.BURN else: raise ValueError(f'Unexpected event type case: {db_event_type}.') is_token0_unknown = event_tuple[6] is_token1_unknown = event_tuple[11] token0: Union[EthereumToken, UnknownEthereumToken] token1: Union[EthereumToken, UnknownEthereumToken] if is_token0_unknown: token0 = deserialize_unknown_ethereum_token_from_db( ethereum_address=event_tuple[7], symbol=event_tuple[8], name=event_tuple[9], decimals=event_tuple[10], ) else: token0 = deserialize_ethereum_token_from_db( identifier=event_tuple[8]) if is_token1_unknown: token1 = deserialize_unknown_ethereum_token_from_db( ethereum_address=event_tuple[12], symbol=event_tuple[13], name=event_tuple[14], decimals=event_tuple[15], ) else: token1 = deserialize_ethereum_token_from_db( identifier=event_tuple[13]) return cls( tx_hash=event_tuple[0], log_index=event_tuple[1], address=string_to_ethereum_address(event_tuple[2]), timestamp=deserialize_timestamp(event_tuple[3]), event_type=event_type, pool_address=string_to_ethereum_address(event_tuple[5]), token0=token0, token1=token1, amount0=deserialize_asset_amount(event_tuple[16]), amount1=deserialize_asset_amount(event_tuple[17]), usd_price=deserialize_price(event_tuple[18]), lp_amount=deserialize_asset_amount(event_tuple[19]), )
import pytest import requests from rotkehlchen.chain.ethereum.typing import string_to_ethereum_address from rotkehlchen.constants.assets import A_ETH, A_EUR from rotkehlchen.constants.misc import ZERO from rotkehlchen.exchanges.data_structures import Trade from rotkehlchen.fval import FVal from rotkehlchen.tests.utils.api import api_url_for, assert_proper_response_with_result from rotkehlchen.tests.utils.exchanges import mock_exchange_data_in_db from rotkehlchen.typing import AssetAmount, Fee, Location, Price, Timestamp, TradeType UNISWAP_ADDR = string_to_ethereum_address('0xcaf012cB72f2c7152b255E091837E3a628F739e7') @pytest.mark.parametrize('added_exchanges', [(Location.BINANCE, Location.POLONIEX)]) @pytest.mark.parametrize('ethereum_accounts', [[UNISWAP_ADDR]]) @pytest.mark.parametrize('ethereum_modules', [['uniswap']]) @pytest.mark.parametrize('start_with_valid_premium', [True]) def test_get_associated_locations( rotkehlchen_api_server_with_exchanges, added_exchanges, ethereum_accounts, # pylint: disable=unused-argument start_with_valid_premium, # pylint: disable=unused-argument ): rotki = rotkehlchen_api_server_with_exchanges.rest_api.rotkehlchen mock_exchange_data_in_db(added_exchanges, rotki) db = rotki.data.db db.add_trades([Trade( timestamp=Timestamp(1595833195),
A_ZRX, ) from rotkehlchen.fval import FVal from rotkehlchen.tests.utils.api import ( api_url_for, assert_error_response, assert_ok_async_response, assert_proper_response_with_result, wait_for_async_task, ) from rotkehlchen.tests.utils.constants import A_API3, A_BAND, A_MFT, A_SYN from rotkehlchen.tests.utils.rotkehlchen import setup_balances from rotkehlchen.typing import AssetAmount, Location, Price, Timestamp, TradeType # Top holder of WBTC-WETH pool (0x1eff8af5d577060ba4ac8a29a13525bb0ee2a3d5) BALANCER_TEST_ADDR1 = string_to_ethereum_address( '0x49a2DcC237a65Cc1F412ed47E0594602f6141936') BALANCER_TEST_ADDR2 = string_to_ethereum_address( '0x029f388aC4D5C8BfF490550ce0853221030E822b') BALANCER_TEST_ADDR3 = string_to_ethereum_address( '0x7716a99194d758c8537F056825b75Dd0C8FDD89f') BALANCER_TEST_ADDR4 = string_to_ethereum_address( '0x231DC6af3C66741f6Cf618884B953DF0e83C1A2A') BALANCER_TEST_ADDR3_POOL1 = EthereumToken.initialize( address=string_to_ethereum_address( '0x59A19D8c652FA0284f44113D0ff9aBa70bd46fB4'), symbol='BPT', protocol='balancer', underlying_tokens=[ UnderlyingToken(address=string_to_ethereum_address( '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'), weight=FVal(0.2)), # noqa: E501 # WETH
def test_avax_query_token_with_info(rotkehlchen_api_server): """Query DAI token to retrieve basic information""" response = requests.get( api_url_for( rotkehlchen_api_server, 'erc20tokeninfoavax', ), json={ 'address': string_to_ethereum_address( '0xba7deebbfc5fa1100fb055a87773e1e99cd3507a'), }, ) result = assert_proper_response_with_result(response) assert result['decimals'] == 18 assert result['symbol'] == 'DAI' assert result['name'] == 'Dai Stablecoin' # Test a contract without decimals/name/symbol methods response_2 = requests.get( api_url_for( rotkehlchen_api_server, 'erc20tokeninfoavax', ), json={ 'address': string_to_ethereum_address( '0x7d655c57f71464B6f83811C55D84009Cd9f5221C'), }, ) result_2 = assert_proper_response_with_result(response_2) assert len(result_2.keys()) == 3 assert all((value is None for value in result_2.values())) # Test an address that is not a contract response_3 = requests.get( api_url_for( rotkehlchen_api_server, 'erc20tokeninfoavax', ), json={ 'address': string_to_ethereum_address( '0x00f195C9ed671173d618e7c03e4A987ef906C739'), }, ) result_3 = assert_proper_response_with_result(response_3) assert len(result_3.keys()) == 3 assert all((value is None for value in result_3.values())) # Test an address that is not valid (this one has extra chars) response_4 = requests.get( api_url_for( rotkehlchen_api_server, 'erc20tokeninfoavax', ), json={ 'address': string_to_ethereum_address( '0x4652D63f4750bCd9d5f5dAds96087485d31554b10F'), }, ) assert_error_response( response=response_4, contained_in_msg='is not an ethereum address', status_code=HTTPStatus.BAD_REQUEST, )
def test_get_trade_with_1_token_pool( rotkehlchen_api_server, ethereum_accounts, # pylint: disable=unused-argument rotki_premium_credentials, # pylint: disable=unused-argument start_with_valid_premium, # pylint: disable=unused-argument ): """ Test the special case of a swap within an 1 token pool. This can probably happen if the controller has since removed tokens from the pool. """ rotki = rotkehlchen_api_server.rest_api.rotkehlchen setup = setup_balances( rotki, ethereum_accounts=ethereum_accounts, btc_accounts=None, original_queries=['zerion', 'logs', 'blocknobytime'], ) with ExitStack() as stack: # patch ethereum/etherscan to not autodetect tokens setup.enter_ethereum_patches(stack) response = requests.get( api_url_for(rotkehlchen_api_server, 'balancertradeshistoryresource'), json={ 'from_timestamp': 1621358338, 'to_timestamp': 1621358340, }, ) result = assert_proper_response_with_result(response) db_trades = rotki.data.db.get_amm_swaps() assert len(db_trades) == 29 address_trades = result[BALANCER_TEST_ADDR4] assert len(address_trades) == 1 assert address_trades[0] == AMMTrade( trade_type=TradeType.BUY, base_asset=A_WETH, quote_asset=A_WBTC, amount=AssetAmount(FVal('0.205421420618533148')), rate=Price(FVal('0.07606382992071615428519015532')), trade_index=0, swaps=[ AMMSwap( tx_hash= '0x4f9e0d8aa660a5d3db276a1ade038f7027f29838dd22d5276571d2e4ea7131ae', # noqa: E501 log_index=84, address=string_to_ethereum_address( BALANCER_TEST_ADDR4), # noqa: E501 from_address=string_to_ethereum_address( '0xFD3dFB524B2dA40c8a6D703c62BE36b5D8540626' ), # noqa: E501 to_address=string_to_ethereum_address( '0x582818356331877553F3E9Cf9557b48e5DdbD54a' ), # noqa: E501 timestamp=Timestamp(1621358339), location=Location.BALANCER, token0=A_WBTC, token1=A_WETH, amount0_in=AssetAmount(FVal('0.01562514')), amount1_in=AssetAmount(ZERO), amount0_out=AssetAmount(ZERO), amount1_out=AssetAmount(FVal('0.205421420618533148')), ), ], ).serialize()
def query_tokens_for_addresses( self, addresses: List[ChecksumEthAddress], force_detection: bool, ) -> TokensReturn: """Queries/detects token balances for a list of addresses If an address's tokens were recently autodetected they are not detected again but the balances are simply queried. Unless force_detection is True. Returns the token balances of each address and the usd prices of the tokens """ log.debug( 'Querying/detecting token balances for all addresses', force_detection=force_detection, ) ignored_assets = self.db.get_ignored_assets() exceptions = [ # Ignore the veCRV balance in token query. It's already detected by # defi SDK as part of locked CRV in Vote Escrowed CRV. Which is the right way # to approach it as there is no way to assign a price to 1 veCRV. It # can be 1 CRV locked for 4 years or 4 CRV locked for 1 year etc. string_to_ethereum_address( '0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2'), # Ignore for now xsushi since is queried by defi SDK. We'll do it for now # since the SDK entry might return other tokens from sushi and we don't # fully support sushi now. string_to_ethereum_address( '0x8798249c2E607446EfB7Ad49eC89dD1865Ff4272'), # Ignore the following tokens. They are old tokens of upgraded contracts which # duplicated the balances at upgrade instead of doing a token swap. # e.g.: https://github.com/rotki/rotki/issues/3548 # TODO: At some point we should actually remove them from the DB and # upgrade possible occurences in the user DB # # Old contract of Fetch.ai string_to_ethereum_address( '0x1D287CC25dAD7cCaF76a26bc660c5F7C8E2a05BD'), ] for asset in ignored_assets: # don't query for the ignored tokens if asset.is_eth_token( ): # type ignore since we know asset is a token exceptions.append( EthereumToken.from_asset( asset).ethereum_address) # type: ignore all_tokens = GlobalDBHandler().get_ethereum_tokens( exceptions=exceptions, except_protocols=['balancer'], ) # With etherscan with chunks > 120, we get request uri too large # so the limitation is not in the gas, but in the request uri length etherscan_chunks = list( get_chunks(all_tokens, n=ETHERSCAN_MAX_TOKEN_CHUNK_LENGTH)) other_chunks = list( get_chunks(all_tokens, n=OTHER_MAX_TOKEN_CHUNK_LENGTH)) now = ts_now() token_usd_price: Dict[EthereumToken, Price] = {} result = {} for address in addresses: saved_list = self.db.get_tokens_for_address_if_time( address=address, current_time=now) if force_detection or saved_list is None: balances = self.detect_tokens_for_address( address=address, token_usd_price=token_usd_price, etherscan_chunks=etherscan_chunks, other_chunks=other_chunks, ) else: if len(saved_list) == 0: continue # Do not query if we know the address has no tokens balances = defaultdict(FVal) self._get_tokens_balance_and_price( address=address, tokens=saved_list, balances=balances, token_usd_price=token_usd_price, call_order=None, # use defaults ) result[address] = balances return result, token_usd_price