Repository: rotki/rotki

Issue:
Fix decoding of governance transactions
There seems to be a new contracts https://arbiscan.io/tx/0xf58c9b1ee6643d6af1fd3b5edbfb311bd86eb3417da561fd1650f12be775d71a and is not properly decode. 

We currently have https://github.com/rotki/rotki/blob/2df089ffdfdd21d2cf9a8b093467f00c7a9e1bd1/rotkehlchen/chain/arbitrum_one/modules/arbitrum_governor/decoder.py#L17 so I suspect that we need to add the new address



Discussion:

Resolving patch:
diff --git a/rotkehlchen/chain/arbitrum_one/modules/arbitrum_governor/constants.py b/rotkehlchen/chain/arbitrum_one/modules/arbitrum_governor/constants.py
new file mode 100644
--- /dev/null
+++ b/rotkehlchen/chain/arbitrum_one/modules/arbitrum_governor/constants.py
@@ -0,0 +1,11 @@
+from typing import Final
+from rotkehlchen.chain.evm.types import string_to_evm_address
+
+
+GOVERNOR_ADDRESSES: Final = (
+    string_to_evm_address('0xf07DeD9dC292157749B6Fd268E37DF6EA38395B9'),  # core governor
+    string_to_evm_address('0x789fC99093B09aD01C34DC7251D0C89ce743e5a4'),  # treasury
+    string_to_evm_address('0x8a1cDA8dee421cD06023470608605934c16A05a0'),  # nominee election
+    string_to_evm_address('0x467923B9AE90BDB36BA88eCA11604D45F13b712C'),  # member election
+    string_to_evm_address('0x6f3a242cA91A119F872f0073BC14BC8a74a315Ad'),  # member removal
+)
diff --git a/rotkehlchen/chain/arbitrum_one/modules/arbitrum_governor/decoder.py b/rotkehlchen/chain/arbitrum_one/modules/arbitrum_governor/decoder.py
--- a/rotkehlchen/chain/arbitrum_one/modules/arbitrum_governor/decoder.py
+++ b/rotkehlchen/chain/arbitrum_one/modules/arbitrum_governor/decoder.py
@@ -1,20 +1,20 @@
 import logging
-from typing import TYPE_CHECKING, Any, Final
+from typing import TYPE_CHECKING, Any
 
 from rotkehlchen.chain.arbitrum_one.constants import ARBITRUM_ONE_CPT_DETAILS, CPT_ARBITRUM_ONE
 from rotkehlchen.chain.evm.decoding.interfaces import GovernableDecoderInterface
 from rotkehlchen.chain.evm.decoding.types import CounterpartyDetails
-from rotkehlchen.chain.evm.types import string_to_evm_address
 from rotkehlchen.logging import RotkehlchenLogsAdapter
 from rotkehlchen.types import ChecksumEvmAddress
 
+from .constants import GOVERNOR_ADDRESSES
+
 if TYPE_CHECKING:
     from rotkehlchen.chain.ethereum.node_inquirer import EthereumInquirer
     from rotkehlchen.chain.evm.decoding.base import BaseDecoderTools
     from rotkehlchen.user_messages import MessagesAggregator
 
 
-GOVERNOR_ADDRESS: Final = string_to_evm_address('0xf07DeD9dC292157749B6Fd268E37DF6EA38395B9')
 logger = logging.getLogger(__name__)
 log = RotkehlchenLogsAdapter(logger)
 
@@ -38,7 +38,7 @@ def __init__(
     # -- DecoderInterface methods
 
     def addresses_to_decoders(self) -> dict[ChecksumEvmAddress, tuple[Any, ...]]:
-        return {GOVERNOR_ADDRESS: (self._decode_vote_cast,)}
+        return dict.fromkeys(GOVERNOR_ADDRESSES, (self._decode_vote_cast,))
 
     @staticmethod
     def counterparties() -> tuple[CounterpartyDetails, ...]:


Test patch:
diff --git a/rotkehlchen/tests/unit/decoders/test_arbitrum_one.py b/rotkehlchen/tests/unit/decoders/test_arbitrum_one.py
--- a/rotkehlchen/tests/unit/decoders/test_arbitrum_one.py
+++ b/rotkehlchen/tests/unit/decoders/test_arbitrum_one.py
@@ -3,7 +3,7 @@
 from rotkehlchen.accounting.structures.balance import Balance
 from rotkehlchen.chain.arbitrum_one.constants import CPT_ARBITRUM_ONE
 from rotkehlchen.chain.arbitrum_one.modules.airdrops.decoder import ARBITRUM_ONE_AIRDROP
-from rotkehlchen.chain.arbitrum_one.modules.arbitrum_governor.decoder import GOVERNOR_ADDRESS
+from rotkehlchen.chain.arbitrum_one.modules.arbitrum_governor.constants import GOVERNOR_ADDRESSES
 from rotkehlchen.chain.evm.decoding.constants import CPT_GAS
 from rotkehlchen.constants import ONE
 from rotkehlchen.constants.assets import A_ARB, A_ETH
@@ -95,6 +95,88 @@ def test_vote_cast(database, arbitrum_one_inquirer, arbitrum_one_accounts):
             location_label=user_address,
             notes='Voted FOR arbitrum_one governance proposal https://www.tally.xyz/gov/arbitrum/proposal/28300903567340237987946172947371304329455149918972967618773111648600015289785',
             counterparty=CPT_ARBITRUM_ONE,
-            address=GOVERNOR_ADDRESS,
+            address=GOVERNOR_ADDRESSES[0],
         )]
     assert expected_events == events
+
+
+@pytest.mark.vcr(filter_query_parameters=['apikey'])
+@pytest.mark.parametrize('arbitrum_one_accounts', [['0xc37b40ABdB939635068d3c5f13E7faF686F03B65']])
+def test_vote_cast_2(database, arbitrum_one_inquirer, arbitrum_one_accounts):
+    tx_hash = deserialize_evm_tx_hash('0xf58c9b1ee6643d6af1fd3b5edbfb311bd86eb3417da561fd1650f12be775d71a')  # noqa: E501
+    events, _ = get_decoded_events_of_transaction(
+        evm_inquirer=arbitrum_one_inquirer,
+        database=database,
+        tx_hash=tx_hash,
+    )
+    timestamp, gas = TimestampMS(1713188011000), '0.00000252921'
+    expected_events = [
+        EvmEvent(
+            sequence_index=0,
+            timestamp=timestamp,
+            location=Location.ARBITRUM_ONE,
+            event_type=HistoryEventType.SPEND,
+            event_subtype=HistoryEventSubType.FEE,
+            asset=A_ETH,
+            balance=Balance(amount=FVal(gas)),
+            location_label=arbitrum_one_accounts[0],
+            notes=f'Burned {gas} ETH for gas',
+            tx_hash=tx_hash,
+            counterparty=CPT_GAS,
+        ), EvmEvent(
+            sequence_index=5,
+            timestamp=timestamp,
+            location=Location.ARBITRUM_ONE,
+            event_type=HistoryEventType.INFORMATIONAL,
+            event_subtype=HistoryEventSubType.GOVERNANCE,
+            asset=A_ETH,
+            balance=Balance(amount=FVal(0)),
+            location_label=arbitrum_one_accounts[0],
+            notes='Voted FOR arbitrum_one governance proposal https://www.tally.xyz/gov/arbitrum/proposal/42524710257895482033293584464762477376427316183960646909542733545381165923770',
+            tx_hash=tx_hash,
+            counterparty=CPT_ARBITRUM_ONE,
+            address=GOVERNOR_ADDRESSES[3],
+        ),
+    ]
+    assert expected_events == events
+
+
+@pytest.mark.vcr(filter_query_parameters=['apikey'])
+@pytest.mark.parametrize('arbitrum_one_accounts', [['0xc37b40ABdB939635068d3c5f13E7faF686F03B65']])
+def test_vote_cast_treasury(database, arbitrum_one_inquirer, arbitrum_one_accounts):
+    tx_hash = deserialize_evm_tx_hash('0x8f5eed6ec89eeccbdfa141b91129118a8294d35a1b44f9e7d570945d17f42765')  # noqa: E501
+    events, _ = get_decoded_events_of_transaction(
+        evm_inquirer=arbitrum_one_inquirer,
+        database=database,
+        tx_hash=tx_hash,
+    )
+    timestamp, gas = TimestampMS(1717152106000), '0.00000270109'
+    expected_events = [
+        EvmEvent(
+            sequence_index=0,
+            timestamp=timestamp,
+            location=Location.ARBITRUM_ONE,
+            event_type=HistoryEventType.SPEND,
+            event_subtype=HistoryEventSubType.FEE,
+            asset=A_ETH,
+            balance=Balance(amount=FVal(gas)),
+            location_label=arbitrum_one_accounts[0],
+            notes=f'Burned {gas} ETH for gas',
+            tx_hash=tx_hash,
+            counterparty=CPT_GAS,
+        ), EvmEvent(
+            sequence_index=10,
+            timestamp=timestamp,
+            location=Location.ARBITRUM_ONE,
+            event_type=HistoryEventType.INFORMATIONAL,
+            event_subtype=HistoryEventSubType.GOVERNANCE,
+            asset=A_ETH,
+            balance=Balance(amount=FVal(0)),
+            location_label=arbitrum_one_accounts[0],
+            notes="Voted AGAINST arbitrum_one governance proposal https://www.tally.xyz/gov/arbitrum/proposal/53472400873981607449547539050199074000442490831067826984987297151333310022877 with reasoning: IMO games or arbitrum is a path that is interesting but the amounts are big and I'm not sure how they adjust to the industry. This is giving a lot of money and might be the wrong path where games that no one enjoy get developed and then nothing happens after it. How the money will be spent is described but I believe the amounts are more than what is needed for such a program",  # noqa: E501
+            tx_hash=tx_hash,
+            counterparty=CPT_ARBITRUM_ONE,
+            address=GOVERNOR_ADDRESSES[1],
+        ),
+    ]
+    assert expected_events == events