Repository: rotki/rotki

Issue:
Eth transactions with no value are not properly shown
## Problem Definition

Transactions with no value and messages are not properly shown in the UI and show as decoding

## Logs

https://etherscan.io/tx/0x52dd71dd287dda86d73f0659c8fee45170432b75c6535f5a55b5c61839fc6f77

![image](https://user-images.githubusercontent.com/5068010/201468719-fc5ae01d-c9a0-4d90-bc53-42f46b70e1c9.png)


### System Description


Operating system: All
Rotki version: 1.26.1



Discussion:

Resolving patch:
diff --git a/rotkehlchen/chain/ethereum/decoding/decoder.py b/rotkehlchen/chain/ethereum/decoding/decoder.py
--- a/rotkehlchen/chain/ethereum/decoding/decoder.py
+++ b/rotkehlchen/chain/ethereum/decoding/decoder.py
@@ -241,13 +241,15 @@ def decode_transaction(
             if event:
                 events.append(event)
 
+        if len(events) == 0 and (eth_event := self._get_eth_transfer_event(transaction)) is not None:  # noqa: E501
+            events = [eth_event]
+
         self.dbevents.add_history_events(write_cursor=write_cursor, history=events)
         write_cursor.execute(
             'INSERT OR IGNORE INTO evm_tx_mappings(tx_hash, blockchain, value) VALUES(?, ?, ?)',  # noqa: E501
             (transaction.tx_hash, 'ETH', HISTORY_MAPPING_DECODED),
         )
-        if events == [] and (eth_event := self._get_eth_transfer_event(transaction)) is not None:
-            events = [eth_event]
+
         return sorted(events, key=lambda x: x.sequence_index, reverse=False)
 
     def get_and_decode_undecoded_transactions(self, limit: Optional[int] = None) -> None:


Test patch:
diff --git a/rotkehlchen/tests/api/test_aave.py b/rotkehlchen/tests/api/test_aave.py
--- a/rotkehlchen/tests/api/test_aave.py
+++ b/rotkehlchen/tests/api/test_aave.py
@@ -76,7 +76,7 @@ def test_query_aave_balances(rotkehlchen_api_server, ethereum_accounts):
         setup.enter_ethereum_patches(stack)
         response = requests.get(api_url_for(
             rotkehlchen_api_server,
-            "aavebalancesresource",
+            'aavebalancesresource',
         ), json={'async_query': async_query})
         if async_query:
             task_id = assert_ok_async_response(response)
@@ -154,7 +154,7 @@ def test_query_aave_balances_module_not_activated(
         setup.enter_ethereum_patches(stack)
         response = requests.get(api_url_for(
             rotkehlchen_api_server,
-            "aavebalancesresource",
+            'aavebalancesresource',
         ), json={'async_query': async_query})
 
         if async_query:
@@ -521,7 +521,7 @@ def _query_simple_aave_history_test_v2(
         setup.enter_ethereum_patches(stack)
         response = requests.get(api_url_for(
             server,
-            "aavehistoryresource",
+            'aavehistoryresource',
         ), json={'async_query': async_query})
         if async_query:
             task_id = assert_ok_async_response(response)
@@ -747,7 +747,7 @@ def _query_borrowing_aave_history_test(setup: BalancesTestSetup, server: APIServ
         setup.enter_ethereum_patches(stack)
         response = requests.get(api_url_for(
             server,
-            "aavehistoryresource",
+            'aavehistoryresource',
         ))
         result = assert_proper_response_with_result(response)
 
@@ -829,7 +829,7 @@ def _test_for_duplicates_and_negatives(setup: BalancesTestSetup, server: APIServ
         setup.enter_ethereum_patches(stack)
         response = requests.get(api_url_for(
             server,
-            "aavehistoryresource",
+            'aavehistoryresource',
         ))
         result = assert_proper_response_with_result(response)
 
@@ -879,7 +879,7 @@ def test_query_aave_history_no_duplicates(rotkehlchen_api_server, ethereum_accou
 def test_query_aave_history_non_premium(rotkehlchen_api_server, ethereum_accounts):  # pylint: disable=unused-argument  # noqa: E501
     response = requests.get(api_url_for(
         rotkehlchen_api_server,
-        "aavehistoryresource",
+        'aavehistoryresource',
     ))
     assert_error_response(
         response=response,
@@ -891,7 +891,7 @@ def test_query_aave_history_non_premium(rotkehlchen_api_server, ethereum_account
 @pytest.mark.parametrize('ethereum_accounts', [['0x01471dB828Cfb96Dcf215c57a7a6493702031EC1']])
 @pytest.mark.parametrize('ethereum_modules', [['aave']])
 def test_query_aave_defi_borrowing(rotkehlchen_api_server, ethereum_accounts):
-    """Checks that the apr/apy values are correctyly returned from the API for a mocked status"""
+    """Checks that the apr/apy values are correctly returned from the API for a mocked position"""
     rotki = rotkehlchen_api_server.rest_api.rotkehlchen
     addrs = string_to_evm_address('0x01471dB828Cfb96Dcf215c57a7a6493702031EC1')
     defi_balances = {
@@ -959,7 +959,7 @@ def test_query_aave_defi_borrowing(rotkehlchen_api_server, ethereum_accounts):
         setup.enter_ethereum_patches(stack)
         response = requests.get(api_url_for(
             rotkehlchen_api_server,
-            "aavebalancesresource",
+            'aavebalancesresource',
         ))
 
     assert response is not None
@@ -968,8 +968,8 @@ def test_query_aave_defi_borrowing(rotkehlchen_api_server, ethereum_accounts):
     assert len(account_data['lending']) == 1
     assert len(account_data['borrowing']) == 1
     variable_borrowing = account_data['borrowing']['eip155:1/erc20:0xdAC17F958D2ee523a2206206994597C13D831ec7']  # noqa: E501
-    assert variable_borrowing['variable_apr'] == '8.85%'
-    assert variable_borrowing['stable_apr'] == '16.85%'
+    assert variable_borrowing['variable_apr'] == '3.75%'
+    assert variable_borrowing['stable_apr'] == '11.87%'
     assert variable_borrowing['balance']['amount'] == '2697.800279'
     variable_borrowing = account_data['lending']['eip155:1/erc20:0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599']  # noqa: E501
     assert variable_borrowing['apy'] == '0.12%'
diff --git a/rotkehlchen/tests/api/test_ethereum_transactions.py b/rotkehlchen/tests/api/test_ethereum_transactions.py
--- a/rotkehlchen/tests/api/test_ethereum_transactions.py
+++ b/rotkehlchen/tests/api/test_ethereum_transactions.py
@@ -18,6 +18,7 @@
 )
 from rotkehlchen.chain.ethereum.decoding.constants import CPT_GAS
 from rotkehlchen.chain.ethereum.structures import EthereumTxReceipt
+from rotkehlchen.chain.ethereum.transactions import EthTransactions
 from rotkehlchen.constants.assets import A_BTC, A_DAI, A_ETH, A_MKR, A_USDT, A_WETH
 from rotkehlchen.constants.limits import FREE_ETH_TX_LIMIT
 from rotkehlchen.constants.misc import ONE
@@ -1299,3 +1300,37 @@ def test_ignored_assets(rotkehlchen_api_server, ethereum_accounts):
     assert result['entries_found'] == 2
     assert result['entries_total'] == 3
     assert result['entries_limit'] == FREE_ETH_TX_LIMIT
+
+
+@pytest.mark.parametrize('ethereum_accounts', [['0x59ABf3837Fa962d6853b4Cc0a19513AA031fd32b']])  # noqa: E501
+@patch.object(EthTransactions, '_get_internal_transactions_for_ranges', lambda *args, **kargs: None)  # noqa: E501
+@patch.object(EthTransactions, '_get_erc20_transfers_for_ranges', lambda *args, **kargs: None)
+def test_no_value_eth_transfer(rotkehlchen_api_server: 'APIServer'):
+    """Test that eth transctions with no value are correctly decoded and returned in the API.
+    In this case we don't need any erc20 or internal transaction, this is why they are omitted
+    in this test.
+    """
+    tx_str = '0x6cbae2712ded4254cc0dbd3daa9528b049c27095b5216a4c52e2e3be3d6905a5'
+    # Make sure that the tranasctions get decoded
+    response = requests.post(
+        api_url_for(
+            rotkehlchen_api_server,
+            'ethereumtransactionsresource',
+        ), json={
+            'async_query': False,
+            'tx_hashes': [tx_str],
+        },
+    )
+
+    # retrieve the transaction
+    response = requests.get(api_url_for(
+        rotkehlchen_api_server,
+        "ethereumtransactionsresource",
+    ), json={'async_query': False, 'from_timestamp': 1668407732, 'to_timestamp': 1668407737})
+
+    result = assert_proper_response_with_result(response)
+    assert len(result['entries']) == 1
+    assert result['entries'][0]['entry']['tx_hash'] == tx_str
+    assert len(result['entries'][0]['decoded_events']) == 1
+    assert result['entries'][0]['decoded_events'][0]['entry']['asset'] == A_ETH
+    assert result['entries'][0]['decoded_events'][0]['entry']['balance']['amount'] == '0'
diff --git a/rotkehlchen/tests/exchanges/test_ftx.py b/rotkehlchen/tests/exchanges/test_ftx.py
--- a/rotkehlchen/tests/exchanges/test_ftx.py
+++ b/rotkehlchen/tests/exchanges/test_ftx.py
@@ -1,3 +1,4 @@
+import os
 import warnings as test_warnings
 from typing import Optional, Set
 from unittest.mock import patch
@@ -561,6 +562,7 @@ def test_query_deposits_withdrawals_unexpected_data(mock_ftx: Ftx):
     )
 
 
+@pytest.mark.skipif('CI' in os.environ, reason='FTX API is unreachable after the incident')
 def test_pagination(mock_ftx: Ftx):
     """Test pagination in the eth/eur market (public endpoint)"""
     # Try pagination good path
diff --git a/rotkehlchen/tests/unit/test_defi_oracles.py b/rotkehlchen/tests/unit/test_defi_oracles.py
--- a/rotkehlchen/tests/unit/test_defi_oracles.py
+++ b/rotkehlchen/tests/unit/test_defi_oracles.py
@@ -114,7 +114,7 @@ def test_pool_with_no_liquidity(inquirer_defi: 'Inquirer'):
     """
     Test that a pool with no liquidity on range is skipped when using uni-v3 oracle
     """
-    old_steram = EvmToken('eip155:1/erc20:0x0Cf0Ee63788A0849fE5297F3407f701E122cC023')
+    old_stream = EvmToken('eip155:1/erc20:0x0Cf0Ee63788A0849fE5297F3407f701E122cC023')
 
     def mock_requests_get(_url, timeout):  # pylint: disable=unused-argument
         response = """{"jsonrpc":"2.0","id":1,"result":"0x0000000000000000000000000000000000000000000000000000000000f2aa4700000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000"}"""  # noqa: E501
@@ -129,5 +129,5 @@ def mock_requests_get(_url, timeout):  # pylint: disable=unused-argument
         wraps=mock_requests_get,
     )
     with etherscan_patch:
-        path = inquirer_defi._uniswapv3.get_pool(old_steram, A_USDC.resolve_to_evm_token())
+        path = inquirer_defi._uniswapv3.get_pool(old_stream, A_USDC.resolve_to_evm_token())
     assert path == []
diff --git a/rotkehlchen/tests/utils/blockchain.py b/rotkehlchen/tests/utils/blockchain.py
--- a/rotkehlchen/tests/utils/blockchain.py
+++ b/rotkehlchen/tests/utils/blockchain.py
@@ -209,7 +209,15 @@ def mock_requests_get(url, *args, **kwargs):
             addr = url[67:109]
             value = eth_map[addr].get('ETH', '0')
             response = f'{{"status":"1","message":"OK","result":{value}}}'
-
+        elif 'https://api.etherscan.io/api?module=proxy&action=eth_call&to=0xeefBa1e63905eF1D7ACbA5a8513c70307C1cE441&data=0x252dba4200000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000086f25b64e1fe4c5162cdeed5245575d32ec549db00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000084e5da1b6800000000000000000000000001471db828cfb96dcf215c57a7a6493702031ec100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000255aa6df07540cb5d3d297f0d0d4d84cb52bc8e600000000000000000000000000000000000000000000000000000000' in url:  # noqa: E501
+            # This is querying ethscan for the aave balances
+            response = '{"jsonrpc":"2.0","id":1,"result":"0x0000000000000000000000000000000000000000000000000000000000f371750000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000"}'  # noqa: E501
+        elif 'https://api.etherscan.io/api?module=proxy&action=eth_call&to=0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9&data=0x35ea6a75000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7' in url:  # noqa: E501
+            # aave lending pool status
+            response = '{"jsonrpc":"2.0","id":1,"result":"0x0000000000000000000000000000000000000000000003e80d060000000000000000000000000000000000000000000000000000038b5d0d773318cf7f0e9085000000000000000000000000000000000000000003b4c95d5d2bb343a6b392450000000000000000000000000000000000000000001edaad248f1f7bbdaff8da0000000000000000000000000000000000000000001f015a6650fa9124a311000000000000000000000000000000000000000000006238800ff08a1b7651888000000000000000000000000000000000000000000000000000000000637392830000000000000000000000003ed3b47dd13ec9a98b44e6204a523e766b225811000000000000000000000000e91d55ab2240594855abd11b3faae801fd4c4687000000000000000000000000531842cebbdd378f8ee36d171d6cc9c4fcf475ec000000000000000000000000515e87cb3fec986050f202a2bbfa362a2188bc3f0000000000000000000000000000000000000000000000000000000000000000"}'  # noqa: E501
+        elif 'https://api.etherscan.io/api?module=proxy&action=eth_call&to=0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9&data=0x35ea6a750000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599' in url:  # noqa: E501
+            # This is querying aave for the status of the pool
+            response = '{"jsonrpc":"2.0","id":1,"result":"0x0000000000000000000000000000000000000000000007d00d08290420081c200000000000000000000000000000000000000000033d6d8eaa28625ea2840ba4000000000000000000000000000000000000000003471d710caeed5ae821e50400000000000000000000000000000000000000000000f487b0cec3822e8c80a60000000000000000000000000000000000000000000aa1b430cd04910319afff000000000000000000000000000000000000000000261ae07f3c498e21e01bfe00000000000000000000000000000000000000000000000000000000636f9edb0000000000000000000000009ff58f4ffb29fa2266ab25e75e2a8b350331165600000000000000000000000051b039b9afe64b78758f8ef091211b5387ea717c0000000000000000000000009c39809dec7f95f5e0713634a4d0701329b3b4d2000000000000000000000000f41e8f817e6c399d1ade102059c454093b24f35b0000000000000000000000000000000000000000000000000000000000000001"}'  # noqa: E501
         elif 'etherscan.io/api?module=account&action=balancemulti' in url:
             queried_accounts = []
             length = 72
@@ -505,24 +513,13 @@ def mock_requests_get(url, *args, **kwargs):
                 if 'ethscan' in original_queries:
                     return original_requests_get(url, *args, **kwargs)
                 response = '{"jsonrpc":"2.0","id":1,"result":"0x0000000000000000000000000000000000000000000000000000000000f370be0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000"}'  # noqa: E501
-            elif 'https://api.etherscan.io/api?module=proxy&action=eth_call&to=0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9&data=0x35ea6a750000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599' in url:  # noqa: E501
-                # This is querying aave for the status of the pool
-                if 'ethscan' in original_queries:
-                    return original_requests_get(url, *args, **kwargs)
-                response = '{"jsonrpc":"2.0","id":1,"result":"0x0000000000000000000000000000000000000000000007d00d08290420081c200000000000000000000000000000000000000000033d6d8eaa28625ea2840ba4000000000000000000000000000000000000000003471d710caeed5ae821e50400000000000000000000000000000000000000000000f487b0cec3822e8c80a60000000000000000000000000000000000000000000aa1b430cd04910319afff000000000000000000000000000000000000000000261ae07f3c498e21e01bfe00000000000000000000000000000000000000000000000000000000636f9edb0000000000000000000000009ff58f4ffb29fa2266ab25e75e2a8b350331165600000000000000000000000051b039b9afe64b78758f8ef091211b5387ea717c0000000000000000000000009c39809dec7f95f5e0713634a4d0701329b3b4d2000000000000000000000000f41e8f817e6c399d1ade102059c454093b24f35b0000000000000000000000000000000000000000000000000000000000000001"}'  # noqa: E501
             elif 'https://api.etherscan.io/api?module=proxy&action=eth_call&to=0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9&data=0x35ea6a75000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7' in url:  # noqa: E501
                 # This is querying aave for the status of the pool
                 if 'ethscan' in original_queries:
                     return original_requests_get(url, *args, **kwargs)
                 response = '{"jsonrpc":"2.0","id":1,"result":"0x0000000000000000000000000000000000000000000003e80d060000000000000000000000000000000000000000000000000000038af6b55802f0e1cb76bbb2000000000000000000000000000000000000000003b458a890598cb1c935e9630000000000000000000000000000000000000000003f555421b1abbbff673b900000000000000000000000000000000000000000004949192d990ec458441edc0000000000000000000000000000000000000000008b75c1de391906a8441edc00000000000000000000000000000000000000000000000000000000636f9f470000000000000000000000003ed3b47dd13ec9a98b44e6204a523e766b225811000000000000000000000000e91d55ab2240594855abd11b3faae801fd4c4687000000000000000000000000531842cebbdd378f8ee36d171d6cc9c4fcf475ec000000000000000000000000515e87cb3fec986050f202a2bbfa362a2188bc3f0000000000000000000000000000000000000000000000000000000000000000"}'  # noqa: E501
-            elif 'https://api.etherscan.io/api?module=proxy&action=eth_call&to=0xeefBa1e63905eF1D7ACbA5a8513c70307C1cE441&data=0x252dba4200000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000086f25b64e1fe4c5162cdeed5245575d32ec549db00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000084e5da1b6800000000000000000000000001471db828cfb96dcf215c57a7a6493702031ec100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000255aa6df07540cb5d3d297f0d0d4d84cb52bc8e600000000000000000000000000000000000000000000000000000000' in url:  # noqa: E501
-                # This is querying ethscan for the aave balances
-                if 'ethscan' in original_queries:
-                    return original_requests_get(url, *args, **kwargs)
-                response = '{"jsonrpc":"2.0","id":1,"result":"0x0000000000000000000000000000000000000000000000000000000000f371750000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000"}'  # noqa: E501
             else:
                 raise AssertionError(f'Unexpected etherscan call during tests: {url}')
-
         else:
             return original_requests_get(url, *args, **kwargs)