We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add Sushiswap support
## Abstract

It seems that Sushiswap transactions are not currently picked up as trades in the profit/loss section of the application

## Motivation

Sushiswap is one of the primary decentralised exchanges and I would imagine that since it is a Uniswap fork, it should take less code to implement this feature than to implement tracking for an entirely different decentralised exchange

## Specification

N/A


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `rotkehlchen/chain/ethereum/interfaces/ammswap/typing.py`
Content:
```
1 import logging
2 from dataclasses import dataclass, field
3 from enum import Enum
4 from typing import Any, DefaultDict, Dict, List, NamedTuple, Optional, Set, Tuple
5 
6 from rotkehlchen.accounting.structures import Balance
7 from rotkehlchen.assets.asset import EthereumToken
8 from rotkehlchen.chain.ethereum.trades import AMMTrade
9 from rotkehlchen.chain.ethereum.typing import string_to_ethereum_address
10 from rotkehlchen.constants import ZERO
11 from rotkehlchen.errors import DeserializationError
12 from rotkehlchen.fval import FVal
13 from rotkehlchen.history.deserialization import deserialize_price
14 from rotkehlchen.serialization.deserialize import (
15     deserialize_asset_amount,
16     deserialize_ethereum_token_from_db,
17     deserialize_timestamp,
18 )
19 from rotkehlchen.typing import AssetAmount, ChecksumEthAddress, Price, Timestamp
20 
21 log = logging.getLogger(__name__)
22 
23 
24 # Get balances
25 @dataclass(init=True, repr=True)
26 class LiquidityPoolAsset:
27     asset: EthereumToken
28     total_amount: Optional[FVal]
29     user_balance: Balance
30     usd_price: Price = Price(ZERO)
31 
32     def serialize(self) -> Dict[str, Any]:
33         return {
34             'asset': self.asset.serialize(),
35             'total_amount': self.total_amount,
36             'user_balance': self.user_balance.serialize(),
37             'usd_price': self.usd_price,
38         }
39 
40 
41 @dataclass(init=True, repr=True)
42 class LiquidityPool:
43     address: ChecksumEthAddress
44     assets: List[LiquidityPoolAsset]
45     total_supply: Optional[FVal]
46     user_balance: Balance
47 
48     def serialize(self) -> Dict[str, Any]:
49         return {
50             'address': self.address,
51             'assets': [asset.serialize() for asset in self.assets],
52             'total_supply': self.total_supply,
53             'user_balance': self.user_balance.serialize(),
54         }
55 
56 
57 AddressToLPBalances = Dict[ChecksumEthAddress, List[LiquidityPool]]
58 DDAddressToLPBalances = DefaultDict[ChecksumEthAddress, List[LiquidityPool]]
59 AssetToPrice = Dict[ChecksumEthAddress, Price]
60 
61 
62 class ProtocolBalance(NamedTuple):
63     """Container structure for uniswap LP balances
64 
65     Known assets are all assets we have an oracle for
66     Unknown assets are those we would have to try to query through uniswap directly
67     """
68     address_balances: AddressToLPBalances
69     known_assets: Set[EthereumToken]
70     unknown_assets: Set[EthereumToken]
71 
72 
73 AddressTrades = Dict[ChecksumEthAddress, List[AMMTrade]]
74 
75 
76 class EventType(Enum):
77     """Supported events"""
78     MINT_UNISWAP = 1
79     BURN_UNISWAP = 2
80     MINT_SUSHISWAP = 3
81     BURN_SUSHISWAP = 4
82 
83     def __str__(self) -> str:
84         if self == EventType.MINT_UNISWAP:
85             return 'mint'
86         if self == EventType.BURN_UNISWAP:
87             return 'burn'
88         if self == EventType.MINT_SUSHISWAP:
89             return 'mint sushiswap'
90         if self == EventType.BURN_SUSHISWAP:
91             return 'burn sushiswap'
92         # else
93         raise RuntimeError(f'Corrupt value {self} for EventType -- Should never happen')
94 
95 
96 LiquidityPoolEventDBTuple = (
97     Tuple[
98         str,  # tx_hash
99         int,  # log_index
100         str,  # address
101         int,  # timestamp
102         str,  # event_type
103         str,  # pool_address
104         str,  # token0_identifier
105         str,  # token1_identifier
106         str,  # amount0
107         str,  # amount1
108         str,  # usd_price
109         str,  # lp_amount
110     ]
111 )
112 
113 
114 class LiquidityPoolEvent(NamedTuple):
115     tx_hash: str
116     log_index: int
117     address: ChecksumEthAddress
118     timestamp: Timestamp
119     event_type: EventType
120     pool_address: ChecksumEthAddress
121     token0: EthereumToken
122     token1: EthereumToken
123     amount0: AssetAmount
124     amount1: AssetAmount
125     usd_price: Price
126     lp_amount: AssetAmount
127 
128     @classmethod
129     def deserialize_from_db(
130             cls,
131             event_tuple: LiquidityPoolEventDBTuple,
132     ) -> 'LiquidityPoolEvent':
133         """Turns a tuple read from DB into an appropriate LiquidityPoolEvent.
134         May raise a DeserializationError if something is wrong with the DB data
135         Event_tuple index - Schema columns
136         ----------------------------------
137         0 - tx_hash
138         1 - log_index
139         2 - address
140         3 - timestamp
141         4 - type
142         5 - pool_address
143         6 - token0_identifier
144         7 - token1_identifier
145         8 - amount0
146         9 - amount1
147         10 - usd_price
148         11 - lp_amount
149         """
150         db_event_type = event_tuple[4]
151         if db_event_type not in {str(event_type) for event_type in EventType}:
152             raise DeserializationError(
153                 f'Failed to deserialize event type. Unknown event: {db_event_type}.',
154             )
155 
156         if db_event_type == str(EventType.MINT_UNISWAP):
157             event_type = EventType.MINT_UNISWAP
158         elif db_event_type == str(EventType.BURN_UNISWAP):
159             event_type = EventType.BURN_UNISWAP
160         elif db_event_type == str(EventType.MINT_SUSHISWAP):
161             event_type = EventType.MINT_SUSHISWAP
162         elif db_event_type == str(EventType.BURN_SUSHISWAP):
163             event_type = EventType.BURN_SUSHISWAP
164         else:
165             raise ValueError(f'Unexpected event type case: {db_event_type}.')
166 
167         token0 = deserialize_ethereum_token_from_db(identifier=event_tuple[6])
168         token1 = deserialize_ethereum_token_from_db(identifier=event_tuple[7])
169 
170         return cls(
171             tx_hash=event_tuple[0],
172             log_index=event_tuple[1],
173             address=string_to_ethereum_address(event_tuple[2]),
174             timestamp=deserialize_timestamp(event_tuple[3]),
175             event_type=event_type,
176             pool_address=string_to_ethereum_address(event_tuple[5]),
177             token0=token0,
178             token1=token1,
179             amount0=deserialize_asset_amount(event_tuple[8]),
180             amount1=deserialize_asset_amount(event_tuple[9]),
181             usd_price=deserialize_price(event_tuple[10]),
182             lp_amount=deserialize_asset_amount(event_tuple[11]),
183         )
184 
185     def to_db_tuple(self) -> LiquidityPoolEventDBTuple:
186         db_tuple = (
187             self.tx_hash,
188             self.log_index,
189             str(self.address),
190             int(self.timestamp),
191             str(self.event_type),
192             str(self.pool_address),
193             self.token0.identifier,
194             self.token1.identifier,
195             str(self.amount0),
196             str(self.amount1),
197             str(self.usd_price),
198             str(self.lp_amount),
199         )
200         return db_tuple
201 
202     def serialize(self) -> Dict[str, Any]:
203         return {
204             'tx_hash': self.tx_hash,
205             'log_index': self.log_index,
206             'timestamp': self.timestamp,
207             'event_type': str(self.event_type),
208             'amount0': str(self.amount0),
209             'amount1': str(self.amount1),
210             'usd_price': str(self.usd_price),
211             'lp_amount': str(self.lp_amount),
212         }
213 
214 
215 class LiquidityPoolEventsBalance(NamedTuple):
216     address: ChecksumEthAddress
217     pool_address: ChecksumEthAddress
218     token0: EthereumToken
219     token1: EthereumToken
220     events: List[LiquidityPoolEvent]
221     profit_loss0: FVal
222     profit_loss1: FVal
223     usd_profit_loss: FVal
224 
225     def serialize(self) -> Dict[str, Any]:
226         return {
227             'address': self.address,
228             'pool_address': self.pool_address,
229             'token0': self.token0.serialize(),
230             'token1': self.token1.serialize(),
231             'events': [event.serialize() for event in self.events],
232             'profit_loss0': str(self.profit_loss0),
233             'profit_loss1': str(self.profit_loss1),
234             'usd_profit_loss': str(self.usd_profit_loss),
235         }
236 
237 
238 @dataclass(init=True, repr=True)
239 class AggregatedAmount:
240     events: List[LiquidityPoolEvent] = field(default_factory=list)
241     profit_loss0: FVal = ZERO
242     profit_loss1: FVal = ZERO
243     usd_profit_loss: FVal = ZERO
244 
245 
246 AddressEvents = Dict[ChecksumEthAddress, List[LiquidityPoolEvent]]
247 DDAddressEvents = DefaultDict[ChecksumEthAddress, List[LiquidityPoolEvent]]
248 AddressEventsBalances = Dict[ChecksumEthAddress, List[LiquidityPoolEventsBalance]]
249
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/rotkehlchen/chain/ethereum/interfaces/ammswap/typing.py b/rotkehlchen/chain/ethereum/interfaces/ammswap/typing.py
--- a/rotkehlchen/chain/ethereum/interfaces/ammswap/typing.py
+++ b/rotkehlchen/chain/ethereum/interfaces/ammswap/typing.py
@@ -80,7 +80,7 @@
     MINT_SUSHISWAP = 3
     BURN_SUSHISWAP = 4
 
-    def __str__(self) -> str:
+    def serialize_for_db(self) -> str:
         if self == EventType.MINT_UNISWAP:
             return 'mint'
         if self == EventType.BURN_UNISWAP:
@@ -92,6 +92,32 @@
         # else
         raise RuntimeError(f'Corrupt value {self} for EventType -- Should never happen')
 
+    @classmethod
+    def deserialize_from_db(
+            cls,
+            value: str,
+    ) -> 'EventType':
+        """May raise DeserializationError if anything is wrong"""
+        if value == 'mint':
+            return EventType.MINT_UNISWAP
+        if value == 'burn':
+            return EventType.BURN_UNISWAP
+        if value == 'mint sushiswap':
+            return EventType.MINT_SUSHISWAP
+        if value == 'burn sushiswap':
+            return EventType.BURN_SUSHISWAP
+
+        raise DeserializationError(f'Unexpected value {value} at AMM EventType deserialization')
+
+    def __str__(self) -> str:
+        if self in (EventType.MINT_UNISWAP, EventType.MINT_SUSHISWAP):
+            return 'mint'
+        if self in (EventType.BURN_UNISWAP, EventType.BURN_SUSHISWAP):
+            return 'burn'
+
+        # else
+        raise RuntimeError(f'Corrupt value {self} for EventType -- Should never happen')
+
 
 LiquidityPoolEventDBTuple = (
     Tuple[
@@ -147,23 +173,7 @@
         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_UNISWAP):
-            event_type = EventType.MINT_UNISWAP
-        elif db_event_type == str(EventType.BURN_UNISWAP):
-            event_type = EventType.BURN_UNISWAP
-        elif db_event_type == str(EventType.MINT_SUSHISWAP):
-            event_type = EventType.MINT_SUSHISWAP
-        elif db_event_type == str(EventType.BURN_SUSHISWAP):
-            event_type = EventType.BURN_SUSHISWAP
-        else:
-            raise ValueError(f'Unexpected event type case: {db_event_type}.')
-
+        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])
 
@@ -188,7 +198,7 @@
             self.log_index,
             str(self.address),
             int(self.timestamp),
-            str(self.event_type),
+            self.event_type.serialize_for_db(),
             str(self.pool_address),
             self.token0.identifier,
             self.token1.identifier,

{"golden_diff": "diff --git a/rotkehlchen/chain/ethereum/interfaces/ammswap/typing.py b/rotkehlchen/chain/ethereum/interfaces/ammswap/typing.py\n--- a/rotkehlchen/chain/ethereum/interfaces/ammswap/typing.py\n+++ b/rotkehlchen/chain/ethereum/interfaces/ammswap/typing.py\n@@ -80,7 +80,7 @@\n     MINT_SUSHISWAP = 3\n     BURN_SUSHISWAP = 4\n \n-    def __str__(self) -> str:\n+    def serialize_for_db(self) -> str:\n         if self == EventType.MINT_UNISWAP:\n             return 'mint'\n         if self == EventType.BURN_UNISWAP:\n@@ -92,6 +92,32 @@\n         # else\n         raise RuntimeError(f'Corrupt value {self} for EventType -- Should never happen')\n \n+    @classmethod\n+    def deserialize_from_db(\n+            cls,\n+            value: str,\n+    ) -> 'EventType':\n+        \"\"\"May raise DeserializationError if anything is wrong\"\"\"\n+        if value == 'mint':\n+            return EventType.MINT_UNISWAP\n+        if value == 'burn':\n+            return EventType.BURN_UNISWAP\n+        if value == 'mint sushiswap':\n+            return EventType.MINT_SUSHISWAP\n+        if value == 'burn sushiswap':\n+            return EventType.BURN_SUSHISWAP\n+\n+        raise DeserializationError(f'Unexpected value {value} at AMM EventType deserialization')\n+\n+    def __str__(self) -> str:\n+        if self in (EventType.MINT_UNISWAP, EventType.MINT_SUSHISWAP):\n+            return 'mint'\n+        if self in (EventType.BURN_UNISWAP, EventType.BURN_SUSHISWAP):\n+            return 'burn'\n+\n+        # else\n+        raise RuntimeError(f'Corrupt value {self} for EventType -- Should never happen')\n+\n \n LiquidityPoolEventDBTuple = (\n     Tuple[\n@@ -147,23 +173,7 @@\n         10 - usd_price\n         11 - lp_amount\n         \"\"\"\n-        db_event_type = event_tuple[4]\n-        if db_event_type not in {str(event_type) for event_type in EventType}:\n-            raise DeserializationError(\n-                f'Failed to deserialize event type. Unknown event: {db_event_type}.',\n-            )\n-\n-        if db_event_type == str(EventType.MINT_UNISWAP):\n-            event_type = EventType.MINT_UNISWAP\n-        elif db_event_type == str(EventType.BURN_UNISWAP):\n-            event_type = EventType.BURN_UNISWAP\n-        elif db_event_type == str(EventType.MINT_SUSHISWAP):\n-            event_type = EventType.MINT_SUSHISWAP\n-        elif db_event_type == str(EventType.BURN_SUSHISWAP):\n-            event_type = EventType.BURN_SUSHISWAP\n-        else:\n-            raise ValueError(f'Unexpected event type case: {db_event_type}.')\n-\n+        event_type = EventType.deserialize_from_db(event_tuple[4])\n         token0 = deserialize_ethereum_token_from_db(identifier=event_tuple[6])\n         token1 = deserialize_ethereum_token_from_db(identifier=event_tuple[7])\n \n@@ -188,7 +198,7 @@\n             self.log_index,\n             str(self.address),\n             int(self.timestamp),\n-            str(self.event_type),\n+            self.event_type.serialize_for_db(),\n             str(self.pool_address),\n             self.token0.identifier,\n             self.token1.identifier,\n", "issue": "Add Sushiswap support\n## Abstract\r\n\r\nIt seems that Sushiswap transactions are not currently picked up as trades in the profit/loss section of the application\r\n\r\n## Motivation\r\n\r\nSushiswap is one of the primary decentralised exchanges and I would imagine that since it is a Uniswap fork, it should take less code to implement this feature than to implement tracking for an entirely different decentralised exchange\r\n\r\n## Specification\r\n\r\nN/A\r\n\n", "before_files": [{"content": "import logging\nfrom dataclasses import dataclass, field\nfrom enum import Enum\nfrom typing import Any, DefaultDict, Dict, List, NamedTuple, Optional, Set, Tuple\n\nfrom rotkehlchen.accounting.structures import Balance\nfrom rotkehlchen.assets.asset import EthereumToken\nfrom rotkehlchen.chain.ethereum.trades import AMMTrade\nfrom rotkehlchen.chain.ethereum.typing import string_to_ethereum_address\nfrom rotkehlchen.constants import ZERO\nfrom rotkehlchen.errors import DeserializationError\nfrom rotkehlchen.fval import FVal\nfrom rotkehlchen.history.deserialization import deserialize_price\nfrom rotkehlchen.serialization.deserialize import (\n    deserialize_asset_amount,\n    deserialize_ethereum_token_from_db,\n    deserialize_timestamp,\n)\nfrom rotkehlchen.typing import AssetAmount, ChecksumEthAddress, Price, Timestamp\n\nlog = logging.getLogger(__name__)\n\n\n# Get balances\n@dataclass(init=True, repr=True)\nclass LiquidityPoolAsset:\n    asset: EthereumToken\n    total_amount: Optional[FVal]\n    user_balance: Balance\n    usd_price: Price = Price(ZERO)\n\n    def serialize(self) -> Dict[str, Any]:\n        return {\n            'asset': self.asset.serialize(),\n            'total_amount': self.total_amount,\n            'user_balance': self.user_balance.serialize(),\n            'usd_price': self.usd_price,\n        }\n\n\n@dataclass(init=True, repr=True)\nclass LiquidityPool:\n    address: ChecksumEthAddress\n    assets: List[LiquidityPoolAsset]\n    total_supply: Optional[FVal]\n    user_balance: Balance\n\n    def serialize(self) -> Dict[str, Any]:\n        return {\n            'address': self.address,\n            'assets': [asset.serialize() for asset in self.assets],\n            'total_supply': self.total_supply,\n            'user_balance': self.user_balance.serialize(),\n        }\n\n\nAddressToLPBalances = Dict[ChecksumEthAddress, List[LiquidityPool]]\nDDAddressToLPBalances = DefaultDict[ChecksumEthAddress, List[LiquidityPool]]\nAssetToPrice = Dict[ChecksumEthAddress, Price]\n\n\nclass ProtocolBalance(NamedTuple):\n    \"\"\"Container structure for uniswap LP balances\n\n    Known assets are all assets we have an oracle for\n    Unknown assets are those we would have to try to query through uniswap directly\n    \"\"\"\n    address_balances: AddressToLPBalances\n    known_assets: Set[EthereumToken]\n    unknown_assets: Set[EthereumToken]\n\n\nAddressTrades = Dict[ChecksumEthAddress, List[AMMTrade]]\n\n\nclass EventType(Enum):\n    \"\"\"Supported events\"\"\"\n    MINT_UNISWAP = 1\n    BURN_UNISWAP = 2\n    MINT_SUSHISWAP = 3\n    BURN_SUSHISWAP = 4\n\n    def __str__(self) -> str:\n        if self == EventType.MINT_UNISWAP:\n            return 'mint'\n        if self == EventType.BURN_UNISWAP:\n            return 'burn'\n        if self == EventType.MINT_SUSHISWAP:\n            return 'mint sushiswap'\n        if self == EventType.BURN_SUSHISWAP:\n            return 'burn sushiswap'\n        # else\n        raise RuntimeError(f'Corrupt value {self} for EventType -- Should never happen')\n\n\nLiquidityPoolEventDBTuple = (\n    Tuple[\n        str,  # tx_hash\n        int,  # log_index\n        str,  # address\n        int,  # timestamp\n        str,  # event_type\n        str,  # pool_address\n        str,  # token0_identifier\n        str,  # token1_identifier\n        str,  # amount0\n        str,  # amount1\n        str,  # usd_price\n        str,  # lp_amount\n    ]\n)\n\n\nclass LiquidityPoolEvent(NamedTuple):\n    tx_hash: str\n    log_index: int\n    address: ChecksumEthAddress\n    timestamp: Timestamp\n    event_type: EventType\n    pool_address: ChecksumEthAddress\n    token0: EthereumToken\n    token1: EthereumToken\n    amount0: AssetAmount\n    amount1: AssetAmount\n    usd_price: Price\n    lp_amount: AssetAmount\n\n    @classmethod\n    def deserialize_from_db(\n            cls,\n            event_tuple: LiquidityPoolEventDBTuple,\n    ) -> 'LiquidityPoolEvent':\n        \"\"\"Turns a tuple read from DB into an appropriate LiquidityPoolEvent.\n        May raise a DeserializationError if something is wrong with the DB data\n        Event_tuple index - Schema columns\n        ----------------------------------\n        0 - tx_hash\n        1 - log_index\n        2 - address\n        3 - timestamp\n        4 - type\n        5 - pool_address\n        6 - token0_identifier\n        7 - token1_identifier\n        8 - amount0\n        9 - amount1\n        10 - usd_price\n        11 - lp_amount\n        \"\"\"\n        db_event_type = event_tuple[4]\n        if db_event_type not in {str(event_type) for event_type in EventType}:\n            raise DeserializationError(\n                f'Failed to deserialize event type. Unknown event: {db_event_type}.',\n            )\n\n        if db_event_type == str(EventType.MINT_UNISWAP):\n            event_type = EventType.MINT_UNISWAP\n        elif db_event_type == str(EventType.BURN_UNISWAP):\n            event_type = EventType.BURN_UNISWAP\n        elif db_event_type == str(EventType.MINT_SUSHISWAP):\n            event_type = EventType.MINT_SUSHISWAP\n        elif db_event_type == str(EventType.BURN_SUSHISWAP):\n            event_type = EventType.BURN_SUSHISWAP\n        else:\n            raise ValueError(f'Unexpected event type case: {db_event_type}.')\n\n        token0 = deserialize_ethereum_token_from_db(identifier=event_tuple[6])\n        token1 = deserialize_ethereum_token_from_db(identifier=event_tuple[7])\n\n        return cls(\n            tx_hash=event_tuple[0],\n            log_index=event_tuple[1],\n            address=string_to_ethereum_address(event_tuple[2]),\n            timestamp=deserialize_timestamp(event_tuple[3]),\n            event_type=event_type,\n            pool_address=string_to_ethereum_address(event_tuple[5]),\n            token0=token0,\n            token1=token1,\n            amount0=deserialize_asset_amount(event_tuple[8]),\n            amount1=deserialize_asset_amount(event_tuple[9]),\n            usd_price=deserialize_price(event_tuple[10]),\n            lp_amount=deserialize_asset_amount(event_tuple[11]),\n        )\n\n    def to_db_tuple(self) -> LiquidityPoolEventDBTuple:\n        db_tuple = (\n            self.tx_hash,\n            self.log_index,\n            str(self.address),\n            int(self.timestamp),\n            str(self.event_type),\n            str(self.pool_address),\n            self.token0.identifier,\n            self.token1.identifier,\n            str(self.amount0),\n            str(self.amount1),\n            str(self.usd_price),\n            str(self.lp_amount),\n        )\n        return db_tuple\n\n    def serialize(self) -> Dict[str, Any]:\n        return {\n            'tx_hash': self.tx_hash,\n            'log_index': self.log_index,\n            'timestamp': self.timestamp,\n            'event_type': str(self.event_type),\n            'amount0': str(self.amount0),\n            'amount1': str(self.amount1),\n            'usd_price': str(self.usd_price),\n            'lp_amount': str(self.lp_amount),\n        }\n\n\nclass LiquidityPoolEventsBalance(NamedTuple):\n    address: ChecksumEthAddress\n    pool_address: ChecksumEthAddress\n    token0: EthereumToken\n    token1: EthereumToken\n    events: List[LiquidityPoolEvent]\n    profit_loss0: FVal\n    profit_loss1: FVal\n    usd_profit_loss: FVal\n\n    def serialize(self) -> Dict[str, Any]:\n        return {\n            'address': self.address,\n            'pool_address': self.pool_address,\n            'token0': self.token0.serialize(),\n            'token1': self.token1.serialize(),\n            'events': [event.serialize() for event in self.events],\n            'profit_loss0': str(self.profit_loss0),\n            'profit_loss1': str(self.profit_loss1),\n            'usd_profit_loss': str(self.usd_profit_loss),\n        }\n\n\n@dataclass(init=True, repr=True)\nclass AggregatedAmount:\n    events: List[LiquidityPoolEvent] = field(default_factory=list)\n    profit_loss0: FVal = ZERO\n    profit_loss1: FVal = ZERO\n    usd_profit_loss: FVal = ZERO\n\n\nAddressEvents = Dict[ChecksumEthAddress, List[LiquidityPoolEvent]]\nDDAddressEvents = DefaultDict[ChecksumEthAddress, List[LiquidityPoolEvent]]\nAddressEventsBalances = Dict[ChecksumEthAddress, List[LiquidityPoolEventsBalance]]\n", "path": "rotkehlchen/chain/ethereum/interfaces/ammswap/typing.py"}], "after_files": [{"content": "import logging\nfrom dataclasses import dataclass, field\nfrom enum import Enum\nfrom typing import Any, DefaultDict, Dict, List, NamedTuple, Optional, Set, Tuple\n\nfrom rotkehlchen.accounting.structures import Balance\nfrom rotkehlchen.assets.asset import EthereumToken\nfrom rotkehlchen.chain.ethereum.trades import AMMTrade\nfrom rotkehlchen.chain.ethereum.typing import string_to_ethereum_address\nfrom rotkehlchen.constants import ZERO\nfrom rotkehlchen.errors import DeserializationError\nfrom rotkehlchen.fval import FVal\nfrom rotkehlchen.history.deserialization import deserialize_price\nfrom rotkehlchen.serialization.deserialize import (\n    deserialize_asset_amount,\n    deserialize_ethereum_token_from_db,\n    deserialize_timestamp,\n)\nfrom rotkehlchen.typing import AssetAmount, ChecksumEthAddress, Price, Timestamp\n\nlog = logging.getLogger(__name__)\n\n\n# Get balances\n@dataclass(init=True, repr=True)\nclass LiquidityPoolAsset:\n    asset: EthereumToken\n    total_amount: Optional[FVal]\n    user_balance: Balance\n    usd_price: Price = Price(ZERO)\n\n    def serialize(self) -> Dict[str, Any]:\n        return {\n            'asset': self.asset.serialize(),\n            'total_amount': self.total_amount,\n            'user_balance': self.user_balance.serialize(),\n            'usd_price': self.usd_price,\n        }\n\n\n@dataclass(init=True, repr=True)\nclass LiquidityPool:\n    address: ChecksumEthAddress\n    assets: List[LiquidityPoolAsset]\n    total_supply: Optional[FVal]\n    user_balance: Balance\n\n    def serialize(self) -> Dict[str, Any]:\n        return {\n            'address': self.address,\n            'assets': [asset.serialize() for asset in self.assets],\n            'total_supply': self.total_supply,\n            'user_balance': self.user_balance.serialize(),\n        }\n\n\nAddressToLPBalances = Dict[ChecksumEthAddress, List[LiquidityPool]]\nDDAddressToLPBalances = DefaultDict[ChecksumEthAddress, List[LiquidityPool]]\nAssetToPrice = Dict[ChecksumEthAddress, Price]\n\n\nclass ProtocolBalance(NamedTuple):\n    \"\"\"Container structure for uniswap LP balances\n\n    Known assets are all assets we have an oracle for\n    Unknown assets are those we would have to try to query through uniswap directly\n    \"\"\"\n    address_balances: AddressToLPBalances\n    known_assets: Set[EthereumToken]\n    unknown_assets: Set[EthereumToken]\n\n\nAddressTrades = Dict[ChecksumEthAddress, List[AMMTrade]]\n\n\nclass EventType(Enum):\n    \"\"\"Supported events\"\"\"\n    MINT_UNISWAP = 1\n    BURN_UNISWAP = 2\n    MINT_SUSHISWAP = 3\n    BURN_SUSHISWAP = 4\n\n    def serialize_for_db(self) -> str:\n        if self == EventType.MINT_UNISWAP:\n            return 'mint'\n        if self == EventType.BURN_UNISWAP:\n            return 'burn'\n        if self == EventType.MINT_SUSHISWAP:\n            return 'mint sushiswap'\n        if self == EventType.BURN_SUSHISWAP:\n            return 'burn sushiswap'\n        # else\n        raise RuntimeError(f'Corrupt value {self} for EventType -- Should never happen')\n\n    @classmethod\n    def deserialize_from_db(\n            cls,\n            value: str,\n    ) -> 'EventType':\n        \"\"\"May raise DeserializationError if anything is wrong\"\"\"\n        if value == 'mint':\n            return EventType.MINT_UNISWAP\n        if value == 'burn':\n            return EventType.BURN_UNISWAP\n        if value == 'mint sushiswap':\n            return EventType.MINT_SUSHISWAP\n        if value == 'burn sushiswap':\n            return EventType.BURN_SUSHISWAP\n\n        raise DeserializationError(f'Unexpected value {value} at AMM EventType deserialization')\n\n    def __str__(self) -> str:\n        if self in (EventType.MINT_UNISWAP, EventType.MINT_SUSHISWAP):\n            return 'mint'\n        if self in (EventType.BURN_UNISWAP, EventType.BURN_SUSHISWAP):\n            return 'burn'\n\n        # else\n        raise RuntimeError(f'Corrupt value {self} for EventType -- Should never happen')\n\n\nLiquidityPoolEventDBTuple = (\n    Tuple[\n        str,  # tx_hash\n        int,  # log_index\n        str,  # address\n        int,  # timestamp\n        str,  # event_type\n        str,  # pool_address\n        str,  # token0_identifier\n        str,  # token1_identifier\n        str,  # amount0\n        str,  # amount1\n        str,  # usd_price\n        str,  # lp_amount\n    ]\n)\n\n\nclass LiquidityPoolEvent(NamedTuple):\n    tx_hash: str\n    log_index: int\n    address: ChecksumEthAddress\n    timestamp: Timestamp\n    event_type: EventType\n    pool_address: ChecksumEthAddress\n    token0: EthereumToken\n    token1: EthereumToken\n    amount0: AssetAmount\n    amount1: AssetAmount\n    usd_price: Price\n    lp_amount: AssetAmount\n\n    @classmethod\n    def deserialize_from_db(\n            cls,\n            event_tuple: LiquidityPoolEventDBTuple,\n    ) -> 'LiquidityPoolEvent':\n        \"\"\"Turns a tuple read from DB into an appropriate LiquidityPoolEvent.\n        May raise a DeserializationError if something is wrong with the DB data\n        Event_tuple index - Schema columns\n        ----------------------------------\n        0 - tx_hash\n        1 - log_index\n        2 - address\n        3 - timestamp\n        4 - type\n        5 - pool_address\n        6 - token0_identifier\n        7 - token1_identifier\n        8 - amount0\n        9 - amount1\n        10 - usd_price\n        11 - lp_amount\n        \"\"\"\n        event_type = EventType.deserialize_from_db(event_tuple[4])\n        token0 = deserialize_ethereum_token_from_db(identifier=event_tuple[6])\n        token1 = deserialize_ethereum_token_from_db(identifier=event_tuple[7])\n\n        return cls(\n            tx_hash=event_tuple[0],\n            log_index=event_tuple[1],\n            address=string_to_ethereum_address(event_tuple[2]),\n            timestamp=deserialize_timestamp(event_tuple[3]),\n            event_type=event_type,\n            pool_address=string_to_ethereum_address(event_tuple[5]),\n            token0=token0,\n            token1=token1,\n            amount0=deserialize_asset_amount(event_tuple[8]),\n            amount1=deserialize_asset_amount(event_tuple[9]),\n            usd_price=deserialize_price(event_tuple[10]),\n            lp_amount=deserialize_asset_amount(event_tuple[11]),\n        )\n\n    def to_db_tuple(self) -> LiquidityPoolEventDBTuple:\n        db_tuple = (\n            self.tx_hash,\n            self.log_index,\n            str(self.address),\n            int(self.timestamp),\n            self.event_type.serialize_for_db(),\n            str(self.pool_address),\n            self.token0.identifier,\n            self.token1.identifier,\n            str(self.amount0),\n            str(self.amount1),\n            str(self.usd_price),\n            str(self.lp_amount),\n        )\n        return db_tuple\n\n    def serialize(self) -> Dict[str, Any]:\n        return {\n            'tx_hash': self.tx_hash,\n            'log_index': self.log_index,\n            'timestamp': self.timestamp,\n            'event_type': str(self.event_type),\n            'amount0': str(self.amount0),\n            'amount1': str(self.amount1),\n            'usd_price': str(self.usd_price),\n            'lp_amount': str(self.lp_amount),\n        }\n\n\nclass LiquidityPoolEventsBalance(NamedTuple):\n    address: ChecksumEthAddress\n    pool_address: ChecksumEthAddress\n    token0: EthereumToken\n    token1: EthereumToken\n    events: List[LiquidityPoolEvent]\n    profit_loss0: FVal\n    profit_loss1: FVal\n    usd_profit_loss: FVal\n\n    def serialize(self) -> Dict[str, Any]:\n        return {\n            'address': self.address,\n            'pool_address': self.pool_address,\n            'token0': self.token0.serialize(),\n            'token1': self.token1.serialize(),\n            'events': [event.serialize() for event in self.events],\n            'profit_loss0': str(self.profit_loss0),\n            'profit_loss1': str(self.profit_loss1),\n            'usd_profit_loss': str(self.usd_profit_loss),\n        }\n\n\n@dataclass(init=True, repr=True)\nclass AggregatedAmount:\n    events: List[LiquidityPoolEvent] = field(default_factory=list)\n    profit_loss0: FVal = ZERO\n    profit_loss1: FVal = ZERO\n    usd_profit_loss: FVal = ZERO\n\n\nAddressEvents = Dict[ChecksumEthAddress, List[LiquidityPoolEvent]]\nDDAddressEvents = DefaultDict[ChecksumEthAddress, List[LiquidityPoolEvent]]\nAddressEventsBalances = Dict[ChecksumEthAddress, List[LiquidityPoolEventsBalance]]\n", "path": "rotkehlchen/chain/ethereum/interfaces/ammswap/typing.py"}]}