Skip to content

Commit

Permalink
Add weth decoder for all supported evm chains
Browse files Browse the repository at this point in the history
  • Loading branch information
iRhonin committed Apr 8, 2024
1 parent 341b2ed commit b45ffc6
Show file tree
Hide file tree
Showing 10 changed files with 557 additions and 41 deletions.
1 change: 1 addition & 0 deletions docs/changelog.rst
Expand Up @@ -2,6 +2,7 @@
Changelog
=========

* :feature:`7708` rotki now properly decode WETH transactions on all supported EVM chains with native ETH
* :feature:`6636` Aave v3 positions and liabilities will now be properly shown in the dashboard.
* :feature:`7423` Users will be able to sort address book entries by displayed name and address.

Expand Down
Empty file.
3 changes: 0 additions & 3 deletions rotkehlchen/chain/ethereum/modules/weth/constants.py

This file was deleted.

32 changes: 0 additions & 32 deletions rotkehlchen/chain/ethereum/modules/weth/decoder.py

This file was deleted.

10 changes: 10 additions & 0 deletions rotkehlchen/chain/evm/decoding/decoder.py
Expand Up @@ -21,6 +21,8 @@
from rotkehlchen.chain.evm.decoding.safe.decoder import SafemultisigDecoder
from rotkehlchen.chain.evm.decoding.socket_bridge.decoder import SocketBridgeDecoder
from rotkehlchen.chain.evm.decoding.types import CounterpartyDetails
from rotkehlchen.chain.evm.decoding.weth.constants import CHAINS_WITHOUT_NATIVE_ETH
from rotkehlchen.chain.evm.decoding.weth.decoder import WethDecoder
from rotkehlchen.chain.evm.structures import EvmTxReceipt, EvmTxReceiptLog
from rotkehlchen.constants import ZERO
from rotkehlchen.db.constants import HISTORY_MAPPING_STATE_DECODED
Expand Down Expand Up @@ -184,6 +186,14 @@ def _add_builtin_decoders(self, rules: DecodingRules) -> None:
self._add_single_decoder(class_name='Oneinchv5', decoder_class=Oneinchv5Decoder, rules=rules) # noqa: E501
self._add_single_decoder(class_name='SocketBridgeDecoder', decoder_class=SocketBridgeDecoder, rules=rules) # noqa: E501

# Excluding Gnosis and Polygon PoS because they dont have ETH as native token
if self.evm_inquirer.chain_id not in CHAINS_WITHOUT_NATIVE_ETH:
self._add_single_decoder(
class_name='Weth',
decoder_class=WethDecoder,
rules=rules,
)

def _add_single_decoder(
self,
class_name: str,
Expand Down
22 changes: 22 additions & 0 deletions rotkehlchen/chain/evm/decoding/weth/constants.py
@@ -0,0 +1,22 @@
import typing
from typing import Final

from rotkehlchen.constants.assets import A_WETH, A_WETH_ARB, A_WETH_BASE, A_WETH_OPT, A_WETH_SCROLL
from rotkehlchen.types import SUPPORTED_CHAIN_IDS, ChainID

CPT_WETH: Final = 'weth'
CHAINS_WITHOUT_NATIVE_ETH: Final = {ChainID.GNOSIS, ChainID.POLYGON_POS}
CHAIN_ID_TO_WETH_MAPPING: Final = {
# A mapping from chain id to WETH asset for every supported evm chain except Gnosis
ChainID.ETHEREUM: A_WETH,
ChainID.ARBITRUM_ONE: A_WETH_ARB,
ChainID.OPTIMISM: A_WETH_OPT,
ChainID.SCROLL: A_WETH_SCROLL,
ChainID.BASE: A_WETH_BASE,
}

# Make sure the CHAIN_ID_TO_WETH_MAPPING has all supported EVM chains with native ETH
assert (
set(CHAIN_ID_TO_WETH_MAPPING.keys()) ==
set(typing.get_args(SUPPORTED_CHAIN_IDS)) - CHAINS_WITHOUT_NATIVE_ETH
)
59 changes: 55 additions & 4 deletions rotkehlchen/chain/evm/decoding/weth/decoder.py
Expand Up @@ -3,7 +3,6 @@

from rotkehlchen.accounting.structures.balance import Balance
from rotkehlchen.assets.asset import CryptoAsset, EvmToken
from rotkehlchen.chain.ethereum.modules.weth.constants import CPT_WETH
from rotkehlchen.chain.ethereum.utils import asset_normalized_value
from rotkehlchen.chain.evm.decoding.interfaces import DecoderInterface
from rotkehlchen.chain.evm.decoding.structures import (
Expand All @@ -13,8 +12,10 @@
)
from rotkehlchen.chain.evm.decoding.types import CounterpartyDetails
from rotkehlchen.chain.evm.decoding.utils import maybe_reshuffle_events
from rotkehlchen.chain.evm.decoding.weth.constants import CHAIN_ID_TO_WETH_MAPPING, CPT_WETH
from rotkehlchen.constants.assets import A_ETH, A_WETH_SCROLL
from rotkehlchen.history.events.structures.types import HistoryEventSubType, HistoryEventType
from rotkehlchen.types import ChecksumEvmAddress
from rotkehlchen.types import ChainID, ChecksumEvmAddress
from rotkehlchen.utils.misc import hex_or_bytes_to_address, hex_or_bytes_to_int

if TYPE_CHECKING:
Expand All @@ -25,6 +26,8 @@

WETH_DEPOSIT_TOPIC = b'\xe1\xff\xfc\xc4\x92=\x04\xb5Y\xf4\xd2\x9a\x8b\xfcl\xda\x04\xeb[\r<F\x07Q\xc2@,\\\\\xc9\x10\x9c' # noqa: E501
WETH_WITHDRAW_TOPIC = b'\x7f\xcfS,\x15\xf0\xa6\xdb\x0b\xd6\xd0\xe08\xbe\xa7\x1d0\xd8\x08\xc7\xd9\x8c\xb3\xbfrh\xa9[\xf5\x08\x1be' # noqa: E501
WETH_DEPOSIT_METHOD = b'\xd0\xe3\r\xb0'
WETH_WITHDRAW_METHOD = b'.\x1a}M'


class WethDecoderBase(DecoderInterface, ABC):
Expand All @@ -47,10 +50,20 @@ def __init__(
self.counterparty = counterparty

def _decode_wrapper(self, context: DecoderContext) -> DecodingOutput:
if context.tx_log.topics[0] == WETH_DEPOSIT_TOPIC:
input_data = context.transaction.input_data

# WETH on Arbitrum is deployed as proxy, we need to check the method
# On the scroll, the contract is different, So we need to check the method.
if context.tx_log.topics[0] == WETH_DEPOSIT_TOPIC or (
self.evm_inquirer.chain_id in {ChainID.ARBITRUM_ONE, ChainID.SCROLL} and
input_data.startswith(WETH_DEPOSIT_METHOD)
):
return self._decode_deposit_event(context)

if context.tx_log.topics[0] == WETH_WITHDRAW_TOPIC:
if context.tx_log.topics[0] == WETH_WITHDRAW_TOPIC or (
self.evm_inquirer.chain_id in {ChainID.ARBITRUM_ONE, ChainID.SCROLL} and
input_data.startswith(WETH_WITHDRAW_METHOD)
):
return self._decode_withdrawal_event(context)

return DEFAULT_DECODING_OUTPUT
Expand Down Expand Up @@ -105,6 +118,22 @@ def _decode_withdrawal_event(self, context: DecoderContext) -> DecodingOutput:
asset=self.base_asset,
)

# This only for withdraw tx on Scroll, Because the unwrap method on WETH on scroll
# generates an additional log (Transfer) which not exists on other chains.
# So because of this additional log, this method will be called twice instead of one,
# therefore we need to skip the second call to avoid creating extra events.
# Check this for example:
# A withdraw on Scroll: https://scrollscan.com/tx/0x88f49633073a7667f93eb888ec2151c26f449cc10afca565a15f8df68ee20f82#eventlog
# A withdraw on Ethereum: https://etherscan.io/tx/0xe5d6fa9c60f595a624e1dd71cb3b28ba9260e90cf3097c5b285b901a97b6246d#eventlog
if self.evm_inquirer.chain_id == ChainID.SCROLL:
for event in context.decoded_events:
if (
event.counterparty == CPT_WETH and
event.asset == A_WETH_SCROLL and
event.balance.amount == withdrawn_amount
):
return DEFAULT_DECODING_OUTPUT # we have already decoded this event

in_event = None
for event in context.decoded_events:
if (
Expand Down Expand Up @@ -149,3 +178,25 @@ def addresses_to_decoders(self) -> dict[ChecksumEvmAddress, tuple[Any, ...]]:
@staticmethod
def counterparties() -> tuple[CounterpartyDetails, ...]:
return (CounterpartyDetails(identifier=CPT_WETH, label='WETH', image='weth.svg'),)


class WethDecoder(WethDecoderBase):
"""
Weth Decoder for all supported EVM chains except Gnosis and Polygon Pos
because of different counterparty and not having ETH as native token.
"""

def __init__(
self,
evm_inquirer: 'EvmNodeInquirer',
base_tools: 'BaseDecoderTools',
msg_aggregator: 'MessagesAggregator',
) -> None:
super().__init__(
evm_inquirer=evm_inquirer,
base_tools=base_tools,
msg_aggregator=msg_aggregator,
base_asset=A_ETH.resolve_to_crypto_asset(),
wrapped_token=CHAIN_ID_TO_WETH_MAPPING[evm_inquirer.chain_id].resolve_to_evm_token(),
counterparty=CPT_WETH,
)
1 change: 1 addition & 0 deletions rotkehlchen/constants/assets.py
Expand Up @@ -277,5 +277,6 @@
A_WETH_ARB = Asset('eip155:42161/erc20:0x82af49447d8a07e3bd95bd0d56f35241523fbab1')
A_WETH_BASE = Asset('eip155:8453/erc20:0x4200000000000000000000000000000000000006')
A_WETH_POLYGON = Asset('eip155:137/erc20:0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619')
A_WETH_SCROLL = Asset('eip155:534352/erc20:0x5300000000000000000000000000000000000004')

CONSTANT_ASSETS = {var_data for var_name, var_data in locals().items() if var_name.startswith('A_')} # noqa: E501
Binary file modified rotkehlchen/data/global.db
Binary file not shown.

0 comments on commit b45ffc6

Please sign in to comment.