def test_upgrade_v1_v2(globaldb): # at this point upgrade should have happened assert globaldb.get_setting_value('version', None) == 2 for identifier, entry in globaldb.get_all_asset_data(mapping=True, serialized=False).items(): if entry.asset_type == AssetType.ETHEREUM_TOKEN: assert identifier == ethaddress_to_identifier(entry.ethereum_address) swapped_for = entry.swapped_for # check the swapped_for key also changed for one we know if entry.name == 'Aurora DAO': assert entry.swapped_for == strethaddress_to_identifier('0xB705268213D593B8FD88d3FDEFF93AFF5CbDcfAE') # noqa: E501 if swapped_for and swapped_for not in ('AM', 'PHB', 'FIRO', 'DIVI', 'SCRT', 'HAI', 'MED', 'NOAHP', 'VET', 'XDC'): # noqa: E501 assert entry.swapped_for.startswith(ETHEREUM_DIRECTIVE) # Check some swapped for that we know should have changed. DIVX -> DIVI asset_data = globaldb.get_asset_data(strethaddress_to_identifier('0x13f11C9905A08ca76e3e853bE63D4f0944326C72'), form_with_incomplete_data=True) # noqa: E501 assert asset_data.swapped_for == 'DIVI' # GNT -> GLM asset_data = globaldb.get_asset_data(strethaddress_to_identifier('0xa74476443119A942dE498590Fe1f2454d7D4aC0d'), form_with_incomplete_data=True) # noqa: E501 assert asset_data.swapped_for == strethaddress_to_identifier('0x7DD9c5Cba05E151C895FDe1CF355C9A1D5DA6429') # noqa: E501 # Make sure the number of assets remained the same cursor = globaldb._conn.cursor() assert cursor.execute('SELECT COUNT(*) from assets').fetchone()[0] == 1886 assert cursor.execute('SELECT COUNT(*) from user_owned_assets').fetchone()[0] == 105 # Make sure that populated underlying assets are still there query = cursor.execute('SELECT * from underlying_tokens_list;') assert query.fetchall() == [ ('0x42Fa37aC7c115bf17ca5DDfcb94b73b91B10B61B', '0.5', '0xBBc2AE13b23d715c30720F079fcd9B4a74093505'), # noqa: E501 ('0x647C4CD779043b3f00a4ccdec550F35Dd18792b3', '0.5', '0xBBc2AE13b23d715c30720F079fcd9B4a74093505'), # noqa: E501 ] # Make sure that the previous custom assets are still in the DB query = cursor.execute( 'SELECT COUNT(*) from assets where identifier IN (?, ?, ?, ?);', ('_ceth_0x35bD01FC9d6D5D81CA9E055Db88Dc49aa2c699A8', '_ceth_0xBBc2AE13b23d715c30720F079fcd9B4a74093505', '_ceth_0x42Fa37aC7c115bf17ca5DDfcb94b73b91B10B61B', '_ceth_0x647C4CD779043b3f00a4ccdec550F35Dd18792b3', ), ) assert query.fetchone()[0] == 4 query = cursor.execute( 'SELECT COUNT(*) from ethereum_tokens where address IN (?, ?, ?, ?);', ('0x35bD01FC9d6D5D81CA9E055Db88Dc49aa2c699A8', '0xBBc2AE13b23d715c30720F079fcd9B4a74093505', '0x42Fa37aC7c115bf17ca5DDfcb94b73b91B10B61B', '0x647C4CD779043b3f00a4ccdec550F35Dd18792b3', ), ) assert query.fetchone()[0] == 4
def asset_from_ftx(ftx_name: str) -> Asset: """May raise: - DeserializationError - UnsupportedAsset - UnknownAsset """ if not isinstance(ftx_name, str): raise DeserializationError( f'Got non-string type {type(ftx_name)} for ftx asset') if ftx_name in UNSUPPORTED_FTX_ASSETS: raise UnsupportedAsset(ftx_name) if ftx_name == 'SRM_LOCKED': name = strethaddress_to_identifier( '0x476c5E26a75bd202a9683ffD34359C0CC15be0fF') # SRM else: name = FTX_TO_WORLD.get(ftx_name, ftx_name) return symbol_to_asset_or_token(name)
def add_ethtoken_initialization(self, var_name: str, address: str) -> str: generated_text = '' token = self.globaldb.get_ethereum_token(address=address) var_swappedfor = 'None' if token.swapped_for: if token.swapped_for in self.id_to_variable: var_swappedfor = self.id_to_variable[token.swapped_for] else: var_swappedfor = f'{strethaddress_to_identifier(address).upper()}_swappedfor' generated_text += self.add_asset_initialization(var_swappedfor, token.swapped_for.identifier) # noqa: E501 name = f'"{token.name}"' if token.name else None symbol = f'\'{token.symbol}\'' if token.symbol else None started = f'Timestamp({token.started})' if token.started else None coingecko = f'\'{token.coingecko}\'' if token.coingecko else None cryptocompare = f'\'{token.cryptocompare}\'' if token.cryptocompare else None protocol = f'\'{token.protocol}\'' if token.protocol else None if token.underlying_tokens is not None: raise ValueError( f'Found token {address} with underlying tokens. Not supported ' f'at constants asset generation yet. Can implement when needed.', ) generated_text += ( f'{var_name} = EthereumToken.initialize(\n' f' address=string_to_ethereum_address(\'{address}\'),\n' f' decimals={token.decimals},\n' f' name={name},\n' f' symbol={symbol},\n' f' started={started},\n' f' swapped_for={var_swappedfor},\n' f' coingecko={coingecko},\n' f' cryptocompare={cryptocompare},\n' f' protocol={protocol},\n' f')\n' f'CONSTANT_ASSETS.append({var_name})\n' ) identifier = strethaddress_to_identifier(address) if identifier in self.id_to_variable: raise ValueError(f'Token with identifier {identifier} and varname {var_name} is defined twice') # noqa: E501 self.id_to_variable[identifier] = var_name return generated_text
def test_asset_and_price_not_found_in_history_processing(accountant): """ Make sure that in history processing if no price is found for a trade it's skipped and an error is logged. Regression for https://github.com/rotki/rotki/issues/432 """ fgp_identifier = strethaddress_to_identifier( '0xd9A8cfe21C232D485065cb62a96866799d4645f7') bad_trades = [{ 'timestamp': 1492685761, 'base_asset': fgp_identifier, 'quote_asset': 'BTC', 'trade_type': 'buy', 'rate': '0.100', 'fee': '0.15', 'fee_currency': fgp_identifier, 'amount': 2.5, 'location': 'kraken', }] result = accounting_history_process( accountant=accountant, start_ts=0, end_ts=1514764799, # 31/12/2017 history_list=bad_trades, loans_list=[], asset_movements_list=[], eth_transaction_list=[], margin_list=[], ) result = result['overview'] errors = accountant.msg_aggregator.consume_errors() assert len(errors) == 1 assert 'due to inability to find a price at that point in time' in errors[ 0] # assert 'due to an asset unknown to cryptocompare being involved' in errors[1] assert FVal(result['total_profit_loss']) == FVal('0')
def test_simple_update(rotkehlchen_api_server, globaldb): """Test that the happy case of update works. - Test that up_to_version argument works - Test that only versions above current local are applied - Test that versions with min/max schema mismatch are skipped """ async_query = random.choice([False, True]) rotki = rotkehlchen_api_server.rest_api.rotkehlchen update_3 = """INSERT INTO ethereum_tokens(address, decimals, protocol) VALUES("0xC2FEC534c461c45533e142f724d0e3930650929c", 18, NULL);INSERT INTO assets(identifier,type, name, symbol,started, swapped_for, coingecko, cryptocompare, details_reference) VALUES("_ceth_0xC2FEC534c461c45533e142f724d0e3930650929c", "C", "AKB token", "AKB",123, NULL, NULL, "AIDU", "0xC2FEC534c461c45533e142f724d0e3930650929c"); * 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("121-ada-FADS-as", "BTC"); * UPDATE assets SET name="Ευρώ" WHERE identifier="EUR"; INSERT INTO assets(identifier,type,name,symbol,started, swapped_for, coingecko, cryptocompare, details_reference) VALUES("EUR", "A","Ευρώ","EUR",NULL, NULL,NULL,NULL, "EUR");INSERT INTO common_asset_details(asset_id, forked) VALUES("EUR", NULL); """ # noqa: E501 update_patch = mock_asset_updates( original_requests_get=requests.get, latest=999999996, updates={ "999999991": { "changes": 1, "min_schema_version": GLOBAL_DB_VERSION, "max_schema_version": GLOBAL_DB_VERSION, }, "999999992": { "changes": 1, "min_schema_version": GLOBAL_DB_VERSION, "max_schema_version": GLOBAL_DB_VERSION, }, "999999993": { "changes": 3, "min_schema_version": GLOBAL_DB_VERSION, "max_schema_version": GLOBAL_DB_VERSION, }, "999999994": { "changes": 5, "min_schema_version": GLOBAL_DB_VERSION + 1, "max_schema_version": GLOBAL_DB_VERSION - 1, }, "999999995": { "changes": 5, "min_schema_version": GLOBAL_DB_VERSION, "max_schema_version": GLOBAL_DB_VERSION, }, "999999996": { "changes": 5, "min_schema_version": GLOBAL_DB_VERSION, "max_schema_version": GLOBAL_DB_VERSION, }, }, sql_actions={ "999999991": "", "999999992": "", "999999993": update_3, "999999994": "", "999999995": "" }, # noqa: E501 ) globaldb.add_setting_value(ASSETS_VERSION_KEY, 999999992) with update_patch: response = requests.get( api_url_for( rotkehlchen_api_server, 'assetupdatesresource', ), json={'async_query': async_query}, ) if async_query: task_id = assert_ok_async_response(response) outcome = wait_for_async_task( rotkehlchen_api_server, task_id, ) result = outcome['result'] assert outcome['message'] == '' else: result = assert_proper_response_with_result(response) assert result['local'] == 999999992 assert result['remote'] == 999999996 assert result[ 'new_changes'] == 13 # changes from 99[3 + 4 + 6], skipping 5 response = requests.post( api_url_for( rotkehlchen_api_server, 'assetupdatesresource', ), json={ 'async_query': async_query, 'up_to_version': 999999995 }, ) if async_query: task_id = assert_ok_async_response(response) outcome = wait_for_async_task( rotkehlchen_api_server, task_id, ) assert outcome['message'] == '' result = outcome['result'] else: result = assert_proper_response_with_result(response) errors = rotki.msg_aggregator.consume_errors() warnings = rotki.msg_aggregator.consume_warnings() assert len(errors) == 0, f'Found errors: {errors}' assert len(warnings) == 1 assert 'Skipping assets update 999999994 since it requires a min schema of' in warnings[ 0] assert result is True assert globaldb.get_setting_value(ASSETS_VERSION_KEY, None) == 999999995 new_token = EthereumToken('0xC2FEC534c461c45533e142f724d0e3930650929c') assert new_token.identifier == strethaddress_to_identifier( '0xC2FEC534c461c45533e142f724d0e3930650929c') # noqa: E501 assert new_token.name == 'AKB token' assert new_token.symbol == 'AKB' assert new_token.asset_type == AssetType.ETHEREUM_TOKEN assert new_token.started == 123 assert new_token.forked is None assert new_token.swapped_for is None assert new_token.coingecko is None assert new_token.cryptocompare == 'AIDU' assert new_token.ethereum_address == '0xC2FEC534c461c45533e142f724d0e3930650929c' assert new_token.decimals == 18 assert new_token.protocol is None new_asset = Asset('121-ada-FADS-as') assert new_asset.identifier == '121-ada-FADS-as' assert new_asset.name == 'A name' assert new_asset.symbol == 'SYMBOL' assert new_asset.asset_type == AssetType.COUNTERPARTY_TOKEN assert new_asset.started is None assert new_asset.forked == 'BTC' assert new_asset.swapped_for is None assert new_asset.coingecko == '' assert new_asset.cryptocompare == '' assert Asset('EUR').name == 'Ευρώ'
def test_foreignkey_conflict(rotkehlchen_api_server, globaldb): """Test that when a conflict that's not solvable happens the entry is ignored One such case is when the update of an asset would violate a foreign key constraint""" async_query = random.choice([False, True]) rotki = rotkehlchen_api_server.rest_api.rotkehlchen update_1 = """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("121-ada-FADS-as", "BTC"); * UPDATE assets SET swapped_for="_ceth_0xA8d35739EE92E69241A2Afd9F513d41021A07972" WHERE identifier="_ceth_0xa74476443119A942dE498590Fe1f2454d7D4aC0d"; INSERT INTO ethereum_tokens(address, decimals, protocol) VALUES("0xa74476443119A942dE498590Fe1f2454d7D4aC0d", 18, NULL);INSERT INTO assets(identifier,type, name, symbol,started, swapped_for, coingecko, cryptocompare, details_reference) VALUES("_ceth_0xa74476443119A942dE498590Fe1f2454d7D4aC0d", "C", "Golem", "GNT", 1478810650, "_ceth_0xA8d35739EE92E69241A2Afd9F513d41021A07972", "golem", NULL, "0xa74476443119A942dE498590Fe1f2454d7D4aC0d"); """ # noqa: E501 update_patch = mock_asset_updates( original_requests_get=requests.get, latest=999999991, updates={ "999999991": { "changes": 2, "min_schema_version": GLOBAL_DB_VERSION, "max_schema_version": GLOBAL_DB_VERSION, } }, sql_actions={"999999991": update_1}, ) globaldb.add_setting_value(ASSETS_VERSION_KEY, 999999990) start_assets_num = len(globaldb.get_all_asset_data(mapping=False)) with update_patch: response = requests.get( api_url_for( rotkehlchen_api_server, 'assetupdatesresource', ), json={'async_query': async_query}, ) if async_query: task_id = assert_ok_async_response(response) outcome = wait_for_async_task( rotkehlchen_api_server, task_id, ) result = outcome['result'] assert outcome['message'] == '' else: result = assert_proper_response_with_result(response) assert result['local'] == 999999990 assert result['remote'] == 999999991 assert result['new_changes'] == 2 response = requests.post( api_url_for( rotkehlchen_api_server, 'assetupdatesresource', ), json={'async_query': async_query}, ) if async_query: task_id = assert_ok_async_response(response) outcome = wait_for_async_task( rotkehlchen_api_server, task_id, ) assert outcome[ 'message'] == 'Found conflicts during assets upgrade' result = outcome['result'] else: result = assert_proper_response_with_result( response, message='Found conflicts during assets upgrade', status_code=HTTPStatus.CONFLICT, ) # Make sure that nothing was committed assert globaldb.get_setting_value(ASSETS_VERSION_KEY, None) == 999999990 assert len( globaldb.get_all_asset_data(mapping=False)) == start_assets_num with pytest.raises(UnknownAsset): Asset('121-ada-FADS-as') errors = rotki.msg_aggregator.consume_errors() warnings = rotki.msg_aggregator.consume_warnings() assert len(errors) == 0, f'Found errors: {errors}' assert len(warnings) == 0, f'Found warnings: {warnings}' # See that we get a conflict expected_result = [{ 'identifier': '_ceth_0xa74476443119A942dE498590Fe1f2454d7D4aC0d', 'local': { 'name': 'Golem', 'symbol': 'GNT', 'asset_type': 'ethereum token', 'started': 1478810650, 'forked': None, 'swapped_for': '_ceth_0x7DD9c5Cba05E151C895FDe1CF355C9A1D5DA6429', 'ethereum_address': '0xa74476443119A942dE498590Fe1f2454d7D4aC0d', 'decimals': 18, 'cryptocompare': None, 'coingecko': 'golem', 'protocol': None, }, 'remote': { 'name': 'Golem', 'symbol': 'GNT', 'asset_type': 'ethereum token', 'started': 1478810650, 'forked': None, 'swapped_for': '_ceth_0xA8d35739EE92E69241A2Afd9F513d41021A07972', 'ethereum_address': '0xa74476443119A942dE498590Fe1f2454d7D4aC0d', 'decimals': 18, 'cryptocompare': None, 'coingecko': 'golem', 'protocol': None, }, }] assert result == expected_result # now try the update again but specify the conflicts resolution conflicts = { '_ceth_0xa74476443119A942dE498590Fe1f2454d7D4aC0d': 'remote' } response = requests.post( api_url_for( rotkehlchen_api_server, 'assetupdatesresource', ), json={ 'async_query': async_query, 'conflicts': conflicts }, ) if async_query: task_id = assert_ok_async_response(response) outcome = wait_for_async_task( rotkehlchen_api_server, task_id, ) assert outcome['message'] == '' result = outcome['result'] else: result = assert_proper_response_with_result( response, message='', status_code=HTTPStatus.OK, ) # check new asset was added and conflict was ignored with an error due to # inability to do anything with the missing swapped_for assert result is True assert globaldb.get_setting_value(ASSETS_VERSION_KEY, None) == 999999991 gnt = EthereumToken('0xa74476443119A942dE498590Fe1f2454d7D4aC0d') assert gnt.identifier == strethaddress_to_identifier( '0xa74476443119A942dE498590Fe1f2454d7D4aC0d') # noqa: E501 assert gnt.name == 'Golem' assert gnt.symbol == 'GNT' assert gnt.asset_type == AssetType.ETHEREUM_TOKEN assert gnt.started == 1478810650 assert gnt.forked is None assert gnt.swapped_for == A_GLM.identifier assert gnt.coingecko == 'golem' assert gnt.cryptocompare is None assert gnt.ethereum_address == '0xa74476443119A942dE498590Fe1f2454d7D4aC0d' assert gnt.decimals == 18 assert gnt.protocol is None new_asset = Asset('121-ada-FADS-as') assert new_asset.identifier == '121-ada-FADS-as' assert new_asset.name == 'A name' assert new_asset.symbol == 'SYMBOL' assert new_asset.asset_type == AssetType.COUNTERPARTY_TOKEN assert new_asset.started is None assert new_asset.forked == 'BTC' assert new_asset.swapped_for is None assert new_asset.coingecko == '' assert new_asset.cryptocompare == '' errors = rotki.msg_aggregator.consume_errors() warnings = rotki.msg_aggregator.consume_warnings() assert len(errors) == 0, f'Found errors: {errors}' assert len(warnings) == 1 assert f'Failed to resolve conflict for {gnt.identifier} in the DB during the v999999991 assets update. Skipping entry' in warnings[ 0] # noqa: E501
def test_update_conflicts(rotkehlchen_api_server, globaldb): """Test that conflicts in an asset update are handled properly""" async_query = random.choice([False, True]) rotki = rotkehlchen_api_server.rest_api.rotkehlchen update_1 = """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("121-ada-FADS-as", "BTC"); * INSERT INTO ethereum_tokens(address, decimals, protocol) VALUES("0x6B175474E89094C44Da98b954EedeAC495271d0F", 8, "maker");INSERT INTO assets(identifier,type, name, symbol,started, swapped_for, coingecko, cryptocompare, details_reference) VALUES("_ceth_0x6B175474E89094C44Da98b954EedeAC495271d0F", "C", "New Multi Collateral DAI", "NDAI", 1573672677, NULL, "dai", NULL, "0x6B175474E89094C44Da98b954EedeAC495271d0F"); * INSERT INTO assets(identifier,type,name,symbol,started, swapped_for, coingecko, cryptocompare, details_reference) VALUES("DASH", "B","Dash","DASH",1337, NULL, "dash-coingecko", NULL, "DASH");INSERT INTO common_asset_details(asset_id, forked) VALUES("DASH", "BTC"); * """ # noqa: E501 update_patch = mock_asset_updates( original_requests_get=requests.get, latest=999999991, updates={ "999999991": { "changes": 3, "min_schema_version": GLOBAL_DB_VERSION, "max_schema_version": GLOBAL_DB_VERSION, } }, sql_actions={"999999991": update_1}, ) globaldb.add_setting_value(ASSETS_VERSION_KEY, 999999990) start_assets_num = len(globaldb.get_all_asset_data(mapping=False)) with update_patch: response = requests.get( api_url_for( rotkehlchen_api_server, 'assetupdatesresource', ), json={'async_query': async_query}, ) if async_query: task_id = assert_ok_async_response(response) outcome = wait_for_async_task( rotkehlchen_api_server, task_id, ) result = outcome['result'] assert outcome['message'] == '' else: result = assert_proper_response_with_result(response) assert result['local'] == 999999990 assert result['remote'] == 999999991 assert result['new_changes'] == 3 response = requests.post( api_url_for( rotkehlchen_api_server, 'assetupdatesresource', ), json={'async_query': async_query}, ) if async_query: task_id = assert_ok_async_response(response) outcome = wait_for_async_task( rotkehlchen_api_server, task_id, ) assert outcome[ 'message'] == 'Found conflicts during assets upgrade' result = outcome['result'] else: result = assert_proper_response_with_result( response, message='Found conflicts during assets upgrade', status_code=HTTPStatus.CONFLICT, ) # Make sure that nothing was committed assert globaldb.get_setting_value(ASSETS_VERSION_KEY, None) == 999999990 assert len( globaldb.get_all_asset_data(mapping=False)) == start_assets_num with pytest.raises(UnknownAsset): Asset('121-ada-FADS-as') errors = rotki.msg_aggregator.consume_errors() warnings = rotki.msg_aggregator.consume_warnings() assert len(errors) == 0, f'Found errors: {errors}' assert len(warnings) == 0, f'Found warnings: {warnings}' # See that we get two conflicts expected_result = [{ 'identifier': '_ceth_0x6B175474E89094C44Da98b954EedeAC495271d0F', 'local': { 'name': 'Multi Collateral Dai', 'symbol': 'DAI', 'asset_type': 'ethereum token', 'started': 1573672677, 'forked': None, 'swapped_for': None, 'ethereum_address': '0x6B175474E89094C44Da98b954EedeAC495271d0F', 'decimals': 18, 'cryptocompare': None, 'coingecko': 'dai', 'protocol': None, }, 'remote': { 'name': 'New Multi Collateral DAI', 'symbol': 'NDAI', 'asset_type': 'ethereum token', 'started': 1573672677, 'forked': None, 'swapped_for': None, 'ethereum_address': '0x6B175474E89094C44Da98b954EedeAC495271d0F', 'decimals': 8, 'cryptocompare': None, 'coingecko': 'dai', 'protocol': 'maker', }, }, { 'identifier': 'DASH', 'local': { 'name': 'Dash', 'symbol': 'DASH', 'asset_type': 'own chain', 'started': 1390095618, 'forked': None, 'swapped_for': None, 'ethereum_address': None, 'decimals': None, 'cryptocompare': None, 'coingecko': 'dash', 'protocol': None, }, 'remote': { 'name': 'Dash', 'symbol': 'DASH', 'asset_type': 'own chain', 'started': 1337, 'forked': 'BTC', 'swapped_for': None, 'ethereum_address': None, 'decimals': None, 'cryptocompare': None, 'coingecko': 'dash-coingecko', 'protocol': None, }, }] assert result == expected_result # now try the update again but specify the conflicts resolution conflicts = { '_ceth_0x6B175474E89094C44Da98b954EedeAC495271d0F': 'remote', 'DASH': 'local' } response = requests.post( api_url_for( rotkehlchen_api_server, 'assetupdatesresource', ), json={ 'async_query': async_query, 'conflicts': conflicts }, ) if async_query: task_id = assert_ok_async_response(response) outcome = wait_for_async_task( rotkehlchen_api_server, task_id, ) assert outcome['message'] == '' result = outcome['result'] else: result = assert_proper_response_with_result( response, message='', status_code=HTTPStatus.OK, ) # check conflicts were solved as per the given choices and new asset also added assert result is True assert globaldb.get_setting_value(ASSETS_VERSION_KEY, None) == 999999991 errors = rotki.msg_aggregator.consume_errors() warnings = rotki.msg_aggregator.consume_warnings() assert len(errors) == 0, f'Found errors: {errors}' assert len(warnings) == 0, f'Found warnings: {warnings}' dai = EthereumToken('0x6B175474E89094C44Da98b954EedeAC495271d0F') assert dai.identifier == strethaddress_to_identifier( '0x6B175474E89094C44Da98b954EedeAC495271d0F') # noqa: E501 assert dai.name == 'New Multi Collateral DAI' assert dai.symbol == 'NDAI' assert dai.asset_type == AssetType.ETHEREUM_TOKEN assert dai.started == 1573672677 assert dai.forked is None assert dai.swapped_for is None assert dai.coingecko == 'dai' assert dai.cryptocompare is None assert dai.ethereum_address == '0x6B175474E89094C44Da98b954EedeAC495271d0F' assert dai.decimals == 8 assert dai.protocol == 'maker' dash = Asset('DASH') assert dash.identifier == 'DASH' assert dash.name == 'Dash' assert dash.symbol == 'DASH' assert dash.asset_type == AssetType.OWN_CHAIN assert dash.started == 1390095618 assert dash.forked is None assert dash.swapped_for is None assert dash.coingecko == 'dash' assert dash.cryptocompare is None new_asset = Asset('121-ada-FADS-as') assert new_asset.identifier == '121-ada-FADS-as' assert new_asset.name == 'A name' assert new_asset.symbol == 'SYMBOL' assert new_asset.asset_type == AssetType.COUNTERPARTY_TOKEN assert new_asset.started is None assert new_asset.forked == 'BTC' assert new_asset.swapped_for is None assert new_asset.coingecko == '' assert new_asset.cryptocompare == ''
weight=FVal(entry[1]), ) WORLD_TO_BITTREX = { # In Rotkehlchen Bitswift is BITS-2 but in Bittrex it's BITS 'BITS-2': 'BITS', # In Rotkehlchen NuBits is USNBT but in Bittrex it's NBT 'USNBT': 'NBT', # In Rotkehlchen BTM-2 is Bytom but in Bittrex it's BTM 'BTM-2': 'BTM', # Bittrex PI shoould map to rotki's PCHAIN strethaddress_to_identifier('0xB9bb08AB7E9Fa0A1356bd4A39eC0ca267E03b0b3'): 'PI', # Bittrex PLA should map to rotki's PlayChip strethaddress_to_identifier('0x0198f46f520F33cd4329bd4bE380a25a90536CD5'): 'PLA', # In Rotkehlchen LUNA-2 is Terra Luna but in Bittrex it's LUNA 'LUNA-2': 'LUNA', # WASP in binance maps to WorldWideAssetExchange in rotki # In Rotkehlchen WorldWideAssetExchange is WAX but in Bittrex it's WASP strethaddress_to_identifier('0x39Bb259F66E1C59d5ABEF88375979b4D20D98022'): 'WAXP', # In Rotkehlchen Validity is RADS, the old name but in Bittrex it's VAL 'RADS': 'VAL', # make sure bittrex matches ADX latest contract
if TYPE_CHECKING: from rotkehlchen.chain.ethereum.typing import CustomEthereumTokenWithIdentifier WORLD_TO_BITTREX = { # In Rotkehlchen Bitswift is BITS-2 but in Bittrex it's BITS 'BITS-2': 'BITS', # In Rotkehlchen NuBits is USNBT but in Bittrex it's NBT 'USNBT': 'NBT', # In Rotkehlchen BTM-2 is Bytom but in Bittrex it's BTM 'BTM-2': 'BTM', # Bittrex PI shoould map to rotki's PCHAIN strethaddress_to_identifier('0xB9bb08AB7E9Fa0A1356bd4A39eC0ca267E03b0b3'): 'PI', # Bittrex PLA should map to rotki's PlayChip strethaddress_to_identifier('0x0198f46f520F33cd4329bd4bE380a25a90536CD5'): 'PLA', # In Rotkehlchen LUNA-2 is Terra Luna but in Bittrex it's LUNA 'LUNA-2': 'LUNA', # WASP in binance maps to WorldWideAssetExchange in rotki # In Rotkehlchen WorldWideAssetExchange is WAX but in Bittrex it's WASP strethaddress_to_identifier('0x39Bb259F66E1C59d5ABEF88375979b4D20D98022'): 'WAXP', # In Rotkehlchen Validity is RADS, the old name but in Bittrex it's VAL 'RADS': 'VAL', # make sure bittrex matches ADX latest contract
'JFI': A_USDT, 'PEARL': A_USDT, 'TAI': A_USDT, 'KLV': A_USDT, 'KRT': A_KRW, 'RVC': A_USDT, 'SDT': A_USDT, 'BAKE': A_BNB, 'BURGER': A_BNB, 'CAKE': A_BNB, 'FILDOWN': A_USDT, 'FILUP': A_USDT, 'YFIDOWN': A_USDT, 'YFIUP': A_USDT, 'SPARTA': A_BNB, strethaddress_to_identifier('0x679131F591B4f369acB8cd8c51E68596806c3916'): A_WETH, # Trustlines # noqa: E501 strethaddress_to_identifier('0xf8aD7dFe656188A23e89da09506Adf7ad9290D5d'): A_USDT, # Blocery A_CDAI: A_DAI, # Compound DAI strethaddress_to_identifier('0x70e36f6BF80a52b3B46b3aF8e106CC0ed743E8e4'): A_COMP, # Compound Comp # noqa: E501 A_CBAT: A_BAT, # Comppound BAT A_CREP: A_REP, # Compound REP strethaddress_to_identifier('0xF5DCe57282A584D2746FaF1593d3121Fcac444dC'): A_SAI, # Compound SAI # noqa: E501 A_CUSDC: A_USDC, # Compound USDC A_CUSDT: A_USDT, # Compound USDT A_CWBTC: A_WBTC, # Compound WBTC strethaddress_to_identifier('0x35A18000230DA775CAc24873d00Ff85BccdeD550'): A_UNI, # Compound UNI # noqa: E501 A_CZRX: A_ZRX, # Compound ZRX strethaddress_to_identifier('0x26CE25148832C04f3d7F26F32478a9fe55197166'): A_USDT, # DEXTools strethaddress_to_identifier('0x0A913beaD80F321E7Ac35285Ee10d9d922659cB7'): A_USDT, # DOS Network token # noqa: E501 strethaddress_to_identifier('0x6B9f031D718dDed0d681c20cB754F97b3BB81b78'): A_USDT, # GEEQ A_STAKE: A_USDT, # xDAI STAKE
weight=FVal(entry[1]), ) WORLD_TO_BITTREX = { # In Rotkehlchen Bitswift is BITS-2 but in Bittrex it's BITS 'BITS-2': 'BITS', # In Rotkehlchen NuBits is USNBT but in Bittrex it's NBT 'USNBT': 'NBT', # In Rotkehlchen BTM-2 is Bytom but in Bittrex it's BTM 'BTM-2': 'BTM', # Bittrex PI shoould map to rotki's PCHAIN strethaddress_to_identifier('0xB9bb08AB7E9Fa0A1356bd4A39eC0ca267E03b0b3'): 'PI', # Bittrex PLA should map to rotki's PlayChip strethaddress_to_identifier('0x0198f46f520F33cd4329bd4bE380a25a90536CD5'): 'PLA', # In Rotkehlchen LUNA-2 is Terra Luna but in Bittrex it's LUNA 'LUNA-2': 'LUNA', # WASP in binance maps to WorldWideAssetExchange in rotki # In Rotkehlchen WorldWideAssetExchange is WAX but in Bittrex it's WASP strethaddress_to_identifier('0x39Bb259F66E1C59d5ABEF88375979b4D20D98022'): 'WAXP', # In Rotkehlchen Validity is RADS, the old name but in Bittrex it's VAL 'RADS': 'VAL', # make sure bittrex matches ADX latest contract
A_BNB, 'BURGER': A_BNB, 'CAKE': A_BNB, 'FILDOWN': A_USDT, 'FILUP': A_USDT, 'YFIDOWN': A_USDT, 'YFIUP': A_USDT, 'SPARTA': A_BNB, strethaddress_to_identifier('0x679131F591B4f369acB8cd8c51E68596806c3916'): A_WETH, # Trustlines # noqa: E501 strethaddress_to_identifier('0xf8aD7dFe656188A23e89da09506Adf7ad9290D5d'): A_USDT, # Blocery A_CDAI: A_DAI, # Compound DAI strethaddress_to_identifier('0x70e36f6BF80a52b3B46b3aF8e106CC0ed743E8e4'): A_COMP, # Compound Comp # noqa: E501 A_CBAT: A_BAT, # Comppound BAT A_CREP: A_REP, # Compound REP strethaddress_to_identifier('0xF5DCe57282A584D2746FaF1593d3121Fcac444dC'): A_SAI, # Compound SAI # noqa: E501 A_CUSDC: A_USDC, # Compound USDC
def test_replace_asset_edge_cases(rotkehlchen_api_server, globaldb): """Test that the edge cases/errors are treated properly in the replace assets endpoint""" rotki = rotkehlchen_api_server.rest_api.rotkehlchen cursor = rotki.data.db.conn.cursor() # Test that completely unknown source asset returns error notexisting_id = 'boo-boo-ga-ga' response = requests.put( api_url_for( rotkehlchen_api_server, 'assetsreplaceresource', ), json={ 'source_identifier': notexisting_id, 'target_asset': 'ICP' }, ) assert_error_response( response=response, contained_in_msg=f'Unknown asset {notexisting_id} provided', status_code=HTTPStatus.CONFLICT, ) # Test that trying to replace an asset that's used as a foreign key elsewhere in # the global DB does not work, error is returned and no changes happen # in the global DB and in the user DB glm_id = strethaddress_to_identifier( '0x7DD9c5Cba05E151C895FDe1CF355C9A1D5DA6429') balances: List[Dict[str, Any]] = [{ 'asset': glm_id, 'label': 'ICP account', 'amount': '50.315', 'location': 'blockchain', }] response = requests.put( api_url_for( rotkehlchen_api_server, 'manuallytrackedbalancesresource', ), json={ 'async_query': False, 'balances': balances }, ) assert_proper_response_with_result(response) global_cursor = globaldb._conn.cursor() def assert_db() -> None: assert global_cursor.execute( 'SELECT COUNT(*) FROM user_owned_assets WHERE asset_id=?', (glm_id, ), ).fetchone()[0] == 1 assert global_cursor.execute( 'SELECT COUNT(*) FROM assets WHERE swapped_for=?', (glm_id, ), ).fetchone()[0] == 1 assert cursor.execute( 'SELECT COUNT(*) FROM assets WHERE identifier=?', (glm_id, ), ).fetchone()[0] == 1 assert_db() response = requests.put( api_url_for( rotkehlchen_api_server, 'assetsreplaceresource', ), json={ 'source_identifier': glm_id, 'target_asset': 'ICP' }, ) assert_error_response( response=response, contained_in_msg='Tried to delete ethereum token with address', status_code=HTTPStatus.CONFLICT, ) assert_db() # Test non-string source identifier response = requests.put( api_url_for( rotkehlchen_api_server, 'assetsreplaceresource', ), json={ 'source_identifier': 55.1, 'target_asset': 'ICP' }, ) assert_error_response( response=response, contained_in_msg='Not a valid string', status_code=HTTPStatus.BAD_REQUEST, ) # Test unknown target asset response = requests.put( api_url_for( rotkehlchen_api_server, 'assetsreplaceresource', ), json={ 'source_identifier': 'ETH', 'target_asset': 'bobobobobo' }, ) assert_error_response( response=response, contained_in_msg='Unknown asset bobobobobo provided', status_code=HTTPStatus.BAD_REQUEST, ) # Test invalid target asset response = requests.put( api_url_for( rotkehlchen_api_server, 'assetsreplaceresource', ), json={ 'source_identifier': 'ETH', 'target_asset': 55 }, ) assert_error_response( response=response, contained_in_msg= 'Tried to initialize an asset out of a non-string identifier', status_code=HTTPStatus.BAD_REQUEST, )
logger = logging.getLogger(__name__) log = RotkehlchenLogsAdapter(logger) COINGECKO_QUERY_RETRY_TIMES = 4 class CoingeckoAssetData(NamedTuple): identifier: str symbol: str name: str description: str image_url: str DELISTED_ASSETS = [ strethaddress_to_identifier('0x0F72714B35a366285Df85886A2eE174601292A17'), 'FLUZ', 'EBCH', 'GOLOS', 'NPER', strethaddress_to_identifier('0xCA29db4221c111888a7e80b12eAc8a266Da3Ee0d'), 'ADN', 'PIX', strethaddress_to_identifier('0xdfdc0D82d96F8fd40ca0CFB4A288955bECEc2088'), 'LKY', strethaddress_to_identifier('0xaFBeC4D65BC7b116d85107FD05d912491029Bf46'), strethaddress_to_identifier('0x37D40510a2F5Bc98AA7a0f7BF4b3453Bcfb90Ac1'), 'BITCAR', strethaddress_to_identifier('0x499A6B77bc25C26bCf8265E2102B1B3dd1617024'), 'OLE', 'ROC',
1479510304: FVal(8.9145), 1483313925: FVal(7.764), 1491062063: FVal(47.865), 1493291104: FVal(53.175), 1493737200: FVal(69.505), 1496979735: FVal(251.36), 1501062063: FVal(175.44), 1511626623: FVal(396.56), 1512561941: FVal(380.34), 1512561942: FVal(380.34), 1539713117: FVal(178.615), 1539713237: FVal(178.615), 1539713238: FVal(178.615), }, }, strethaddress_to_identifier('0x255Aa6DF07540Cb5d3d297f0D0D4D84cb52bc8e6'): { 'EUR': { 1512561942: ZERO, }, }, 'CHF': { 'EUR': { 1496979735: FVal(1.001), }, }, 'LTC': { 'EUR': { 1493650800: FVal(14.07), 1493737200: FVal(14.56), },
class CoingeckoImageURLs(NamedTuple): thumb: str small: str large: str class CoingeckoAssetData(NamedTuple): identifier: str symbol: str name: str description: str images: CoingeckoImageURLs DELISTED_ASSETS = [ strethaddress_to_identifier('0x0F72714B35a366285Df85886A2eE174601292A17'), 'FLUZ', 'EBCH', 'GOLOS', 'NPER', strethaddress_to_identifier('0xCA29db4221c111888a7e80b12eAc8a266Da3Ee0d'), 'ADN', 'PIX', strethaddress_to_identifier('0xdfdc0D82d96F8fd40ca0CFB4A288955bECEc2088'), 'LKY', strethaddress_to_identifier('0xaFBeC4D65BC7b116d85107FD05d912491029Bf46'), strethaddress_to_identifier('0x37D40510a2F5Bc98AA7a0f7BF4b3453Bcfb90Ac1'), 'BITCAR', strethaddress_to_identifier('0x499A6B77bc25C26bCf8265E2102B1B3dd1617024'), 'OLE', 'ROC',
logger = logging.getLogger(__name__) log = RotkehlchenLogsAdapter(logger) COINGECKO_QUERY_RETRY_TIMES = 4 class CoingeckoAssetData(NamedTuple): identifier: str symbol: str name: str description: str image_url: str DELISTED_ASSETS = [ strethaddress_to_identifier('0x0F72714B35a366285Df85886A2eE174601292A17'), 'FLUZ', 'EBCH', 'GOLOS', 'NPER', strethaddress_to_identifier('0xCA29db4221c111888a7e80b12eAc8a266Da3Ee0d'), 'ADN', 'PIX', strethaddress_to_identifier('0xdfdc0D82d96F8fd40ca0CFB4A288955bECEc2088'), 'LKY', strethaddress_to_identifier('0xaFBeC4D65BC7b116d85107FD05d912491029Bf46'), strethaddress_to_identifier('0x37D40510a2F5Bc98AA7a0f7BF4b3453Bcfb90Ac1'), 'BITCAR', strethaddress_to_identifier('0x499A6B77bc25C26bCf8265E2102B1B3dd1617024'), 'OLE', 'ROC',