Repository: rotki/rotki

Issue:
NFT gallery breaks with special NFT (tbd)
## Problem Definition

If one starts traveling the NFT gallery the application freezes and one has to close it an open again. This is caused by specific NFT that needs to be found. I'm on it atm

## Logs

Neither the backend or the electron logs report any issue related to this freeze. The console log shows this

![image](https://user-images.githubusercontent.com/5068010/135713076-d459771c-1d64-4e20-ae23-dcd8c0337074.png)

Took a look at heap memory and was about 30MB. Currently trying to find the NFT that triggers this

### System Description

Operating system: Windows & linux
Rotki version: 1.21.0



Discussion:

Resolving patch:
diff --git a/rotkehlchen/externalapis/opensea.py b/rotkehlchen/externalapis/opensea.py
--- a/rotkehlchen/externalapis/opensea.py
+++ b/rotkehlchen/externalapis/opensea.py
@@ -216,6 +216,8 @@ def _deserialize_nft(
             price_in_eth = max(last_price_in_eth, floor_price)
             price_in_usd = price_in_eth * eth_usd_price
             token_id = entry['asset_contract']['address'] + '_' + entry['token_id']
+            if entry['asset_contract']['asset_contract_type'] == 'semi-fungible':
+                token_id += f'_{str(owner_address)}'
             return NFT(
                 token_identifier=NFT_DIRECTIVE + token_id,
                 background_color=entry['background_color'],


Test patch:
diff --git a/rotkehlchen/tests/api/test_nfts.py b/rotkehlchen/tests/api/test_nfts.py
--- a/rotkehlchen/tests/api/test_nfts.py
+++ b/rotkehlchen/tests/api/test_nfts.py
@@ -15,6 +15,8 @@
 )
 
 TEST_ACC1 = '0x2B888954421b424C5D3D9Ce9bB67c9bD47537d12'
+TEST_ACC2 = '0x3ba6eb0e4327b96ade6d4f3b578724208a590cef'
+TEST_ACC3 = '0xc21a5ee89d306353e065a6dd5779470de395dbac'
 
 
 @pytest.mark.parametrize('ethereum_accounts', [[TEST_ACC1]])
@@ -60,3 +62,26 @@ def test_nft_query(rotkehlchen_api_server, start_with_valid_premium):
             assert isinstance(entry['collection']['description'], str)
             assert entry['collection']['large_image'].startswith('https://')
             break
+
+
+@pytest.mark.parametrize('ethereum_accounts', [[TEST_ACC2, TEST_ACC3]])
+@pytest.mark.parametrize('start_with_valid_premium', [True])
+@pytest.mark.parametrize('ethereum_modules', [['nfts']])
+def test_nft_ids_are_unique(rotkehlchen_api_server):
+    """Check that if two accounts hold the same semi-fungible token we don't have duplicate ids"""
+    response = requests.get(api_url_for(
+        rotkehlchen_api_server,
+        'nftsresource',
+    ), json={'async_query': False})
+
+    result = assert_proper_response_with_result(response)
+    # get the ids from the query result
+    ids_1 = [nft['token_identifier'] for nft in result['addresses'][TEST_ACC2]]
+    ids_2 = [nft['token_identifier'] for nft in result['addresses'][TEST_ACC3]]
+    # Check that two possible duplicates are between the NFT ids
+    expected_id = '_nft_0xfaff15c6cdaca61a4f87d329689293e07c98f578_1'
+    assert any([expected_id in nft_id for nft_id in ids_1])
+    assert any([expected_id in nft_id for nft_id in ids_2])
+    all_ids = ids_1 + ids_2
+    set_of_ids = set(all_ids)
+    assert len(all_ids) == len(set_of_ids)