예제 #1
0
 def __init__(
     self,
     database: 'DBHandler',
     ethereum_manager: 'EthereumManager',
     eth_transactions: 'EthTransactions',
     msg_aggregator: MessagesAggregator,
 ):
     self.database = database
     self.all_counterparties: Set[str] = set()
     self.ethereum_manager = ethereum_manager
     self.eth_transactions = eth_transactions
     self.msg_aggregator = msg_aggregator
     self.dbethtx = DBEthTx(self.database)
     self.dbevents = DBHistoryEvents(self.database)
     self.base = BaseDecoderTools(database=database)
     self.event_rules = [  # rules to try for all tx receipt logs decoding
         self._maybe_decode_erc20_approve,
         self._maybe_decode_erc20_721_transfer,
         self._maybe_enrich_transfers,
         self._maybe_decode_governance,
     ]
     self.token_enricher_rules: List[Callable] = [
     ]  # enrichers to run for token transfers
     self.initialize_all_decoders()
     self.undecoded_tx_query_lock = Semaphore()
예제 #2
0
    def _maybe_query_ethereum_transactions(self) -> None:
        """Schedules the ethereum transaction query task if enough time has passed"""
        accounts = self.database.get_blockchain_accounts().eth
        if len(accounts) == 0:
            return

        now = ts_now()
        dbethtx = DBEthTx(self.database)
        queriable_accounts = []
        for account in accounts:
            _, end_ts = dbethtx.get_queried_range(account)
            if now - max(self.last_eth_tx_query_ts[account],
                         end_ts) > ETH_TX_QUERY_FREQUENCY:
                queriable_accounts.append(account)

        if len(queriable_accounts) == 0:
            return

        address = random.choice(queriable_accounts)
        task_name = f'Query ethereum transactions for {address}'
        log.debug(f'Scheduling task to {task_name}')
        self.greenlet_manager.spawn_and_track(
            after_seconds=None,
            task_name=task_name,
            exception_is_error=True,
            method=self.eth_transactions.single_address_query_transactions,
            address=address,
            start_ts=0,
            end_ts=now,
        )
        self.last_eth_tx_query_ts[address] = now
예제 #3
0
def test_maybe_schedule_ethereum_txreceipts(
    task_manager,
    ethereum_manager,
    eth_transactions,
    database,
    one_receipt_in_db,
):
    task_manager.potential_tasks = [
        task_manager._maybe_schedule_ethereum_txreceipts
    ]  # pylint: disable=protected-member  # noqa: E501
    _, receipts = setup_ethereum_transactions_test(
        database=database,
        transaction_already_queried=True,
        one_receipt_in_db=one_receipt_in_db,
    )

    dbethtx = DBEthTx(database)
    timeout = 10
    tx_hash_1 = hexstring_to_bytes(
        '0x692f9a6083e905bdeca4f0293f3473d7a287260547f8cbccc38c5cb01591fcda'
    )  # noqa: E501
    tx_hash_2 = hexstring_to_bytes(
        '0x6beab9409a8f3bd11f82081e99e856466a7daf5f04cca173192f79e78ed53a77'
    )  # noqa: E501
    receipt_get_patch = patch.object(
        ethereum_manager,
        'get_transaction_receipt',
        wraps=ethereum_manager.get_transaction_receipt)  # pylint: disable=protected-member  # noqa: E501
    queried_receipts = set()
    try:
        with gevent.Timeout(timeout):
            with receipt_get_patch as receipt_task_mock:
                task_manager.schedule()
                while True:
                    if len(queried_receipts) == 2:
                        break

                    for txhash in (tx_hash_1, tx_hash_2):
                        if dbethtx.get_receipt(txhash) is not None:
                            queried_receipts.add(txhash)

                    gevent.sleep(.3)

                task_manager.schedule()
                gevent.sleep(.5)
                assert receipt_task_mock.call_count == 1 if one_receipt_in_db else 2, '2nd schedule should do nothing'  # noqa: E501

    except gevent.Timeout as e:
        raise AssertionError(
            f'receipts query was not completed within {timeout} seconds'
        ) from e  # noqa: E501

    receipt1 = eth_transactions.get_or_query_transaction_receipt(tx_hash_1)
    assert receipt1 == receipts[0]
    receipt2 = eth_transactions.get_or_query_transaction_receipt(tx_hash_2)
    assert receipt2 == receipts[1]
def test_tx_decode(evm_transaction_decoder, database):
    dbethtx = DBEthTx(database)
    addr1 = '0x2B888954421b424C5D3D9Ce9bB67c9bD47537d12'
    approve_tx_hash = deserialize_evm_tx_hash('0x5cc0e6e62753551313412492296d5e57bea0a9d1ce507cc96aa4aa076c5bde7a')  # noqa: E501
    transactions = dbethtx.get_ethereum_transactions(
        filter_=ETHTransactionsFilterQuery.make(
            addresses=[addr1],
            tx_hash=approve_tx_hash,
        ),
        has_premium=True,
    )
    decoder = evm_transaction_decoder
    with patch.object(decoder, 'decode_transaction', wraps=decoder.decode_transaction) as decode_mock:  # noqa: E501
        for tx in transactions:
            receipt = dbethtx.get_receipt(tx.tx_hash)
            assert receipt is not None, 'all receipts should be queried in the test DB'
            events = decoder.get_or_decode_transaction_events(tx, receipt, ignore_cache=False)
            if tx.tx_hash == approve_tx_hash:
                assert len(events) == 2
                assert_events_equal(events[0], HistoryBaseEntry(
                    # The no-member is due to https://github.com/PyCQA/pylint/issues/3162
                    event_identifier=approve_tx_hash.hex(),  # pylint: disable=no-member
                    sequence_index=0,
                    timestamp=1569924574000,
                    location=Location.BLOCKCHAIN,
                    location_label=addr1,
                    asset=A_ETH,
                    balance=Balance(amount=FVal('0.000030921')),
                    # The no-member is due to https://github.com/PyCQA/pylint/issues/3162
                    notes=f'Burned 0.000030921 ETH in gas from {addr1}',
                    event_type=HistoryEventType.SPEND,
                    event_subtype=HistoryEventSubType.FEE,
                    counterparty=CPT_GAS,
                ))
                assert_events_equal(events[1], HistoryBaseEntry(
                    # The no-member is due to https://github.com/PyCQA/pylint/issues/3162
                    event_identifier=approve_tx_hash.hex(),  # pylint: disable=no-member
                    sequence_index=163,
                    timestamp=1569924574000,
                    location=Location.BLOCKCHAIN,
                    location_label=addr1,
                    asset=A_SAI,
                    balance=Balance(amount=1),
                    notes=f'Approve 1 SAI of {addr1} for spending by 0xdf869FAD6dB91f437B59F1EdEFab319493D4C4cE',  # noqa: E501
                    event_type=HistoryEventType.INFORMATIONAL,
                    event_subtype=HistoryEventSubType.APPROVE,
                    counterparty='0xdf869FAD6dB91f437B59F1EdEFab319493D4C4cE',
                ))

        assert decode_mock.call_count == len(transactions)
        # now go again, and see that no more decoding happens as it's all pulled from the DB
        for tx in transactions:
            receipt = dbethtx.get_receipt(tx.tx_hash)
            assert receipt is not None, 'all receipts should be queried in the test DB'
            events = decoder.get_or_decode_transaction_events(tx, receipt, ignore_cache=False)
        assert decode_mock.call_count == len(transactions)
예제 #5
0
파일: transactions.py 프로젝트: rotki/rotki
    def get_or_query_transaction_receipt(
            self,
            tx_hash: str,
    ) -> Optional['EthereumTxReceipt']:
        """
        Gets the receipt from the DB if it exist. If not queries the chain for it,
        saves it in the DB and then returns it.

        Also if the actual transaction does not exist in the DB it queries it and saves it there.

        May raise:

        - DeserializationError
        - RemoteError
        """
        tx_hash_b = hexstring_to_bytes(tx_hash)
        dbethtx = DBEthTx(self.database)
        # If the transaction is not in the DB then query it and add it
        result, _ = dbethtx.get_ethereum_transactions(ETHTransactionsFilterQuery.make(tx_hash=tx_hash_b))  # noqa: E501
        if len(result) == 0:
            transaction = self.ethereum.get_transaction_by_hash(tx_hash)
            if transaction is None:
                return None  # hash does not correspond to a transaction

            dbethtx.add_ethereum_transactions([transaction])

        tx_receipt = dbethtx.get_receipt(tx_hash_b)
        if tx_receipt is not None:
            return tx_receipt

        # not in the DB, so we need to query the chain for it
        tx_receipt_data = self.ethereum.get_transaction_receipt(tx_hash=tx_hash)
        dbethtx.add_receipt_data(tx_receipt_data)
        tx_receipt = dbethtx.get_receipt(tx_hash_b)
        return tx_receipt
예제 #6
0
파일: transactions.py 프로젝트: rotki/rotki
    def query(
            self,
            filter_query: ETHTransactionsFilterQuery,
            with_limit: bool = False,
            only_cache: bool = False,
    ) -> Tuple[List[EthereumTransaction], int]:
        """Queries for all transactions (normal AND internal) of an ethereum
        address or of all addresses.
        Returns a list of all transactions filtered and sorted according to the parameters.

        If `with_limit` is true then the api limit is applied

        if `recent_first` is true then the transactions are returned with the most
        recent first on the list

        May raise:
        - RemoteError if etherscan is used and there is a problem with reaching it or
        with parsing the response.
        - pysqlcipher3.dbapi2.OperationalError if the SQL query fails due to
        invalid filtering arguments.
        """
        query_addresses = filter_query.addresses

        if query_addresses is not None:
            accounts = query_addresses
        else:
            accounts = self.database.get_blockchain_accounts().eth

        if only_cache is False:
            f_from_ts = filter_query.from_ts
            f_to_ts = filter_query.to_ts
            from_ts = Timestamp(0) if f_from_ts is None else f_from_ts
            to_ts = ts_now() if f_to_ts is None else f_to_ts
            for address in accounts:
                self.single_address_query_transactions(
                    address=address,
                    start_ts=from_ts,
                    end_ts=to_ts,
                )

        dbethtx = DBEthTx(self.database)
        transactions, total_filter_count = dbethtx.get_ethereum_transactions(filter_=filter_query)
        return (
            self._return_transactions_maybe_limit(
                requested_addresses=query_addresses,
                transactions=transactions,
                with_limit=with_limit,
            ),
            total_filter_count,
        )
예제 #7
0
    def get_or_query_transaction_receipt(
        self,
        tx_hash: EVMTxHash,
    ) -> 'EthereumTxReceipt':
        """
        Gets the receipt from the DB if it exists. If not queries the chain for it,
        saves it in the DB and then returns it.

        Also if the actual transaction does not exist in the DB it queries it and saves it there.

        May raise:

        - DeserializationError
        - RemoteError if the transaction hash can't be found in any of the connected nodes
        """
        dbethtx = DBEthTx(self.database)
        # If the transaction is not in the DB then query it and add it
        result = dbethtx.get_ethereum_transactions(
            filter_=ETHTransactionsFilterQuery.make(tx_hash=tx_hash),
            has_premium=True,  # we don't need any limiting here
        )
        if len(result) == 0:
            transaction = self.ethereum.get_transaction_by_hash(tx_hash)
            dbethtx.add_ethereum_transactions([transaction],
                                              relevant_address=None)
            self._get_internal_transactions_for_ranges(
                address=transaction.from_address,
                start_ts=transaction.timestamp,
                end_ts=transaction.timestamp,
            )
            self._get_erc20_transfers_for_ranges(
                address=transaction.from_address,
                start_ts=transaction.timestamp,
                end_ts=transaction.timestamp,
            )

        tx_receipt = dbethtx.get_receipt(tx_hash)
        if tx_receipt is not None:
            return tx_receipt

        # not in the DB, so we need to query the chain for it
        tx_receipt_data = self.ethereum.get_transaction_receipt(
            tx_hash=tx_hash)
        dbethtx.add_receipt_data(tx_receipt_data)
        tx_receipt = dbethtx.get_receipt(tx_hash)
        return tx_receipt  # type: ignore  # tx_receipt was just added in the DB so should be there  # noqa: E501
예제 #8
0
파일: transactions.py 프로젝트: rotki/rotki
    def single_address_query_transactions(
            self,
            address: ChecksumEthAddress,
            start_ts: Timestamp,
            end_ts: Timestamp,
    ) -> None:
        """Only queries new transactions and adds them to the DB"""
        ranges = DBQueryRanges(self.database)
        ranges_to_query = ranges.get_location_query_ranges(
            location_string=f'ethtxs_{address}',
            start_ts=start_ts,
            end_ts=end_ts,
        )
        new_transactions = []
        dbethtx = DBEthTx(self.database)
        for query_start_ts, query_end_ts in ranges_to_query:
            try:
                new_transactions.extend(self.ethereum.etherscan.get_transactions(
                    account=address,
                    from_ts=query_start_ts,
                    to_ts=query_end_ts,
                ))
            except RemoteError as e:
                self.ethereum.msg_aggregator.add_error(
                    f'Got error "{str(e)}" while querying ethereum transactions '
                    f'from Etherscan. Transactions not added to the DB '
                    f'from_ts: {query_start_ts} '
                    f'to_ts: {query_end_ts} ',
                )

        # add new transactions to the DB
        if new_transactions != []:
            dbethtx.add_ethereum_transactions(new_transactions)

        # and also set the last queried timestamps for the address
        ranges.update_used_query_range(
            location_string=f'ethtxs_{address}',
            start_ts=start_ts,
            end_ts=end_ts,
            ranges_to_query=ranges_to_query,
        )
예제 #9
0
def test_purge_ethereum_transaction_data(rotkehlchen_api_server):
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen
    db = DBEthTx(rotki.data.db)
    db.add_ethereum_transactions([
        EthereumTransaction(
            tx_hash=bytes(),
            timestamp=1,
            block_number=1,
            from_address=make_ethereum_address(),
            to_address=make_ethereum_address(),
            value=FVal(1),
            gas=FVal(1),
            gas_price=FVal(1),
            gas_used=FVal(1),
            input_data=bytes(),
            nonce=1,
        )
    ], )
    filter_ = ETHTransactionsFilterQuery.make()

    result, filter_count = db.get_ethereum_transactions(filter_)
    assert len(result) == 1
    assert filter_count == 1
    response = requests.delete(
        api_url_for(
            rotkehlchen_api_server,
            "ethereumtransactionsresource",
        ), )
    assert_simple_ok_response(response)
    result, filter_count = db.get_ethereum_transactions(filter_)
    assert len(result) == 0
    assert filter_count == 0
예제 #10
0
    def query(
        self,
        filter_query: ETHTransactionsFilterQuery,
        has_premium: bool = False,
        only_cache: bool = False,
    ) -> Tuple[List[EthereumTransaction], int]:
        """Queries for all transactions of an ethereum address or of all addresses.

        Returns a list of all transactions filtered and sorted according to the parameters.

        May raise:
        - RemoteError if etherscan is used and there is a problem with reaching it or
        with parsing the response.
        - pysqlcipher3.dbapi2.OperationalError if the SQL query fails due to
        invalid filtering arguments.
        """
        query_addresses = filter_query.addresses

        if query_addresses is not None:
            accounts = query_addresses
        else:
            accounts = self.database.get_blockchain_accounts().eth

        if only_cache is False:
            f_from_ts = filter_query.from_ts
            f_to_ts = filter_query.to_ts
            from_ts = Timestamp(0) if f_from_ts is None else f_from_ts
            to_ts = ts_now() if f_to_ts is None else f_to_ts
            for address in accounts:
                self.single_address_query_transactions(
                    address=address,
                    start_ts=from_ts,
                    end_ts=to_ts,
                )

        dbethtx = DBEthTx(self.database)
        return dbethtx.get_ethereum_transactions_and_limit_info(
            filter_=filter_query,
            has_premium=has_premium,
        )
예제 #11
0
    def _maybe_decode_evm_transactions(self) -> None:
        """Schedules the evm transaction decoding task

        The DB check happens first here to see if scheduling would even be needed.
        But the DB query will happen again inside the query task while having the
        lock acquired.
        """
        dbethtx = DBEthTx(self.database)
        hashes = dbethtx.get_transaction_hashes_not_decoded(
            limit=TX_DECODING_LIMIT)
        hashes_length = len(hashes)
        if hashes_length > 0:
            task_name = f'decode {hashes_length} evm trasactions'
            log.debug(f'Scheduling periodic task to {task_name}')
            self.greenlet_manager.spawn_and_track(
                after_seconds=None,
                task_name=task_name,
                exception_is_error=True,
                method=self.evm_tx_decoder.
                get_and_decode_undecoded_transactions,
                limit=TX_DECODING_LIMIT,
            )
예제 #12
0
    def _maybe_schedule_ethereum_txreceipts(self) -> None:
        """Schedules the ethereum transaction receipts query task

        The DB check happens first here to see if scheduling would even be needed.
        But the DB query will happen again inside the query task while having the
        lock acquired.
        """
        dbethtx = DBEthTx(self.database)
        hash_results = dbethtx.get_transaction_hashes_no_receipt(
            tx_filter_query=None, limit=TX_RECEIPTS_QUERY_LIMIT)  # noqa: E501
        if len(hash_results) == 0:
            return

        task_name = f'Query {len(hash_results)} ethereum transactions receipts'
        log.debug(f'Scheduling task to {task_name}')
        self.greenlet_manager.spawn_and_track(
            after_seconds=None,
            task_name=task_name,
            exception_is_error=True,
            method=self.eth_transactions.
            get_receipts_for_transactions_missing_them,
            limit=TX_RECEIPTS_QUERY_LIMIT,
        )
예제 #13
0
    def get_receipts_for_transactions_missing_them(self,
                                                   limit: Optional[int] = None
                                                   ) -> None:
        """
        Searches the database for up to `limit` transactions that have no corresponding receipt
        and for each one of them queries the receipt and saves it in the DB.

        It's protected by a lock to not enter the same code twice
        (i.e. from periodic tasks and from pnl report history events gathering)
        """
        with self.missing_receipts_lock:
            dbethtx = DBEthTx(self.database)
            hash_results = dbethtx.get_transaction_hashes_no_receipt(
                tx_filter_query=None,
                limit=limit,
            )

            if len(hash_results) == 0:
                return  # nothing to do

            for entry in hash_results:
                tx_receipt_data = self.ethereum.get_transaction_receipt(
                    tx_hash=entry)
                dbethtx.add_receipt_data(tx_receipt_data)
예제 #14
0
def test_purge_ethereum_transaction_data(rotkehlchen_api_server):
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen
    addr1 = make_ethereum_address()
    rotki.data.db.add_blockchain_accounts(
        blockchain=SupportedBlockchain.ETHEREUM,
        account_data=[
            BlockchainAccountData(address=addr1),
        ],
    )
    db = DBEthTx(rotki.data.db)
    db.add_ethereum_transactions(
        [
            EthereumTransaction(
                tx_hash=make_evm_tx_hash(bytes()),
                timestamp=1,
                block_number=1,
                from_address=addr1,
                to_address=make_ethereum_address(),
                value=FVal(1),
                gas=FVal(1),
                gas_price=FVal(1),
                gas_used=FVal(1),
                input_data=bytes(),
                nonce=1,
            )
        ],
        relevant_address=addr1,
    )
    filter_ = ETHTransactionsFilterQuery.make()

    result, filter_count = db.get_ethereum_transactions_and_limit_info(
        filter_, True)
    assert len(result) == 1
    assert filter_count == 1
    response = requests.delete(
        api_url_for(
            rotkehlchen_api_server,
            'ethereumtransactionsresource',
        ), )
    assert_simple_ok_response(response)
    result, filter_count = db.get_ethereum_transactions_and_limit_info(
        filter_, True)
    assert len(result) == 0
    assert filter_count == 0
예제 #15
0
def test_kyber_legacy_new_contract(database, ethereum_manager,
                                   eth_transactions):
    """Data for trade taken from
    https://etherscan.io/tx/0xe80928d5e21f9628c047af1f8b191cbffbb6b8b9945adb502cfb3af152552f22
    """
    msg_aggregator = MessagesAggregator()
    tx_hex = '0xe80928d5e21f9628c047af1f8b191cbffbb6b8b9945adb502cfb3af152552f22'
    evmhash = deserialize_evm_tx_hash(tx_hex)
    transaction = EthereumTransaction(
        tx_hash=evmhash,
        timestamp=1644182638,
        block_number=14154915,
        from_address='0x5340F6faff9BF55F66C16Db6Bf9E020d987F87D0',
        to_address='0x9AAb3f75489902f3a48495025729a0AF77d4b11e',
        value=0,
        gas=2784000,
        gas_price=71000000000,
        gas_used=938231,
        input_data=hexstring_to_bytes(
            '0xae591d54000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000001e52b2aa0000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd520000000000000000000000005340f6faff9bf55f66c16db6bf9e020d987f87d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000003ef569a751d10e0000000000000000000000000de63aef60307655405835da74ba02ce4db1a42fb000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000000'
        ),  # noqa: E501
        nonce=41,
    )
    receipt = EthereumTxReceipt(
        tx_hash=evmhash,
        contract_address=None,
        status=True,
        type=0,
        logs=[
            EthereumTxReceiptLog(
                log_index=349,
                data=hexstring_to_bytes(
                    '0x00000000000000000000000000000000000000000000000000000001e52b2aa0'
                ),  # noqa: E501
                address=string_to_ethereum_address(
                    '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'),
                removed=False,
                topics=[
                    hexstring_to_bytes(
                        '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'
                    ),  # noqa: E501
                    hexstring_to_bytes(
                        '0x0000000000000000000000005340f6faff9bf55f66c16db6bf9e020d987f87d0'
                    ),  # noqa: E501
                    hexstring_to_bytes(
                        '0x0000000000000000000000007c66550c9c730b6fdd4c03bc2e73c5462c5f7acc'
                    ),  # noqa: E501
                ],
            ),
            EthereumTxReceiptLog(
                log_index=369,
                data=hexstring_to_bytes(
                    '0x000000000000000000000000000000000000000000000083a3ee0140f345d2d8'
                ),  # noqa: E501
                address=string_to_ethereum_address(
                    '0xD533a949740bb3306d119CC777fa900bA034cd52'),
                removed=False,
                topics=[
                    hexstring_to_bytes(
                        '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'
                    ),  # noqa: E501
                    hexstring_to_bytes(
                        '0x0000000000000000000000007c66550c9c730b6fdd4c03bc2e73c5462c5f7acc'
                    ),  # noqa: E501
                    hexstring_to_bytes(
                        '0x0000000000000000000000005340f6faff9bf55f66c16db6bf9e020d987f87d0'
                    ),  # noqa: E501
                ],
            ),
            EthereumTxReceiptLog(
                log_index=372,
                data=hexstring_to_bytes(
                    '0x000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd520000000000000000000000005340f6faff9bf55f66c16db6bf9e020d987f87d000000000000000000000000000000000000000000000000000000001e52b2aa0000000000000000000000000000000000000000000000083a3ee0140f345d2d8000000000000000000000000de63aef60307655405835da74ba02ce4db1a42fb0000000000000000000000000000000000000000000000000000000000000012'
                ),  # noqa: E501
                address=string_to_ethereum_address(
                    '0x9AAb3f75489902f3a48495025729a0AF77d4b11e'),
                removed=False,
                topics=[
                    hexstring_to_bytes(
                        '0xf724b4df6617473612b53d7f88ecc6ea983074b30960a049fcd0657ffe808083'
                    ),  # noqa: E501
                    hexstring_to_bytes(
                        '0x0000000000000000000000005340f6faff9bf55f66c16db6bf9e020d987f87d0'
                    ),  # noqa: E501
                ],
            ),
        ],
    )

    dbethtx = DBEthTx(database)
    dbethtx.add_ethereum_transactions([transaction], relevant_address=None)
    decoder = EVMTransactionDecoder(
        database=database,
        ethereum_manager=ethereum_manager,
        eth_transactions=eth_transactions,
        msg_aggregator=msg_aggregator,
    )
    events = decoder.decode_transaction(transaction=transaction,
                                        tx_receipt=receipt)

    assert len(events) == 3
    expected_events = [
        HistoryBaseEntry(
            event_identifier=
            '0xe80928d5e21f9628c047af1f8b191cbffbb6b8b9945adb502cfb3af152552f22',
            sequence_index=0,
            timestamp=1644182638000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.FEE,
            asset=A_ETH,
            balance=Balance(
                amount=FVal(0.066614401),
                usd_value=FVal(0),
            ),
            location_label='0x5340F6faff9BF55F66C16Db6Bf9E020d987F87D0',
            notes=
            'Burned 0.066614401 ETH in gas from 0x5340F6faff9BF55F66C16Db6Bf9E020d987F87D0',  # noqa: E501
            counterparty=CPT_GAS,
        ),
        HistoryBaseEntry(
            event_identifier=
            '0xe80928d5e21f9628c047af1f8b191cbffbb6b8b9945adb502cfb3af152552f22',
            sequence_index=350,
            timestamp=1644182638000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.TRADE,
            event_subtype=HistoryEventSubType.SPEND,
            asset=A_USDC,
            balance=Balance(amount=FVal(8139.77872), usd_value=FVal(0)),
            location_label='0x5340F6faff9BF55F66C16Db6Bf9E020d987F87D0',
            notes='Swap 8139.77872 USDC in kyber',
            counterparty='kyber legacy',
        ),
        HistoryBaseEntry(
            event_identifier=
            '0xe80928d5e21f9628c047af1f8b191cbffbb6b8b9945adb502cfb3af152552f22',
            sequence_index=370,
            timestamp=1644182638000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.TRADE,
            event_subtype=HistoryEventSubType.RECEIVE,
            asset=A_CRV,
            balance=Balance(amount=FVal('2428.33585390706162556'),
                            usd_value=FVal(0)),
            location_label='0x5340F6faff9BF55F66C16Db6Bf9E020d987F87D0',
            notes='Receive 2428.33585390706162556 CRV from kyber swap',
            counterparty='kyber legacy',
        ),
    ]
    assert events == expected_events
예제 #16
0
def test_gitcoin_claim(database, ethereum_manager, eth_transactions):
    """Data for claim taken from
    https://etherscan.io/tx/0x0e22cbdbac56c785f186bec44d715ab0834ceeadd96573c030f2fae1550b64fa
    """
    msg_aggregator = MessagesAggregator()
    tx_hex = '0x0e22cbdbac56c785f186bec44d715ab0834ceeadd96573c030f2fae1550b64fa'
    evmhash = deserialize_evm_tx_hash(tx_hex)
    transaction = EthereumTransaction(
        tx_hash=evmhash,
        timestamp=1646375440,
        block_number=14351442,
        from_address='0xdF5CEF8Dc0CEA8DC200F09280915d1CD7a016BDe',
        to_address='0xDE3e5a990bCE7fC60a6f017e7c4a95fc4939299E',
        value=0,
        gas=171249,
        gas_price=22990000000,
        gas_used=171249,
        input_data=hexstring_to_bytes('0x09c5eabe000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002e43f7658fd000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000013500050000a7823d6f1e31569f51861e345b30c6bebf70ebe70000000000009cf6f6a78083ca3e2a662d6dd1703c939c8ace2e268d88ad09518695c6c3712ac10a214be5109a655671000927c00101006401867f7a4d000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000003f615ba21bc6cc5d4a6d798c5950cc5c42937fbd00000000000000000000000000000000000000000000000007392088b40d14000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000004000000000000000000000000006c187e1b71ffbee4429003bb846c1b3eb1610000000000000000000000000000000000000000000000000000048c52ee05b140000000000000000000000000000000000000000000000000000000000000000000000000000000000000105041b1c1c1c73a08c7605fa9c69f068338cb7cd1c8dd21189cbe56f4cc66cff8dc7f0b0c8cc8c64433ea24643b893c9062beae6a05656b1df5643a242533d63925144c3e5c7dfd0509fb3c4232cfdb4c500e942a95b23439b3e18bab4a40057e1bdfae2d9967025b3f8fdca13354b25250c0d7fa9e4b472dc97df1f0cd0f595dc266d09e711628b3a63c1a6e4c83a11d3655891e31901eacf73b927e10bfbe6b0d5ed808cc228d606779a19a7dfb7393956b4fada14eaef8f6de6ee3824e67d6df18cc2d55f00cf869cc920135a94fb4abc213dc43e97812879d9efab046e4fffb931dcb55e5aa2b86f6a848408fea42cd221df99f1720b2ce22830498d78d04e1d083ba12800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'),  # noqa: E501
        nonce=12,
    )
    receipt = EthereumTxReceipt(
        tx_hash=evmhash,
        contract_address=None,
        status=True,
        type=0,
        logs=[
            EthereumTxReceiptLog(
                log_index=473,
                data=hexstring_to_bytes('0x00000000000000000000000000000000000000000000000eb9078f7826f80000'),  # noqa: E501
                address=string_to_ethereum_address('0xDe30da39c46104798bB5aA3fe8B9e0e1F348163F'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000de3e5a990bce7fc60a6f017e7c4a95fc4939299e'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000df5cef8dc0cea8dc200f09280915d1cd7a016bde'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=6,
                data=hexstring_to_bytes('0x0000000000000000000000000000000000000000000000000000000000018580000000000000000000000000df5cef8dc0cea8dc200f09280915d1cd7a016bde00000000000000000000000000000000000000000000000eb9078f7826f80000bcfadbb867130fed43327b6c801903ab2afb5134ba5f3d47d2647ab858d5e49e'),  # noqa: E501
                address=string_to_ethereum_address('0xDE3e5a990bCE7fC60a6f017e7c4a95fc4939299E'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0x04672052dcb6b5b19a9cc2ec1b8f447f1f5e47b5e24cfa5e4ffb640d63ca2be7'),  # noqa: E501
                ],
            ),
        ],
    )

    dbethtx = DBEthTx(database)
    dbethtx.add_ethereum_transactions([transaction], relevant_address=None)
    decoder = EVMTransactionDecoder(
        database=database,
        ethereum_manager=ethereum_manager,
        eth_transactions=eth_transactions,
        msg_aggregator=msg_aggregator,
    )
    events = decoder.decode_transaction(transaction=transaction, tx_receipt=receipt)
    assert len(events) == 2
    expected_events = [
        HistoryBaseEntry(
            event_identifier='0x0e22cbdbac56c785f186bec44d715ab0834ceeadd96573c030f2fae1550b64fa',
            sequence_index=0,
            timestamp=1646375440000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.FEE,
            asset=A_ETH,
            balance=Balance(
                amount=FVal(0.00393701451),
                usd_value=ZERO,
            ),
            location_label='0xdF5CEF8Dc0CEA8DC200F09280915d1CD7a016BDe',
            notes='Burned 0.00393701451 ETH in gas from 0xdF5CEF8Dc0CEA8DC200F09280915d1CD7a016BDe',  # noqa: E501
            counterparty=CPT_GAS,
        ), HistoryBaseEntry(
            event_identifier='0x0e22cbdbac56c785f186bec44d715ab0834ceeadd96573c030f2fae1550b64fa',
            sequence_index=474,
            timestamp=1646375440000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.RECEIVE,
            event_subtype=HistoryEventSubType.AIRDROP,
            asset=EthereumToken('0xDe30da39c46104798bB5aA3fe8B9e0e1F348163F'),
            balance=Balance(amount=FVal('271.5872'), usd_value=ZERO),
            location_label='0xdF5CEF8Dc0CEA8DC200F09280915d1CD7a016BDe',
            notes='Claim 271.5872 GTC from the GTC airdrop',
            counterparty='0xDE3e5a990bCE7fC60a6f017e7c4a95fc4939299E',
        ),
    ]
    assert events == expected_events
예제 #17
0
def test_1inch_claim(database, ethereum_manager, eth_transactions):
    """Data for claim taken from
    https://etherscan.io/tx/0x0582a0db79de3fa21d3b92a8658e0b1034c51ea54a8e06ea84fbb91d41b8fe17
    """
    msg_aggregator = MessagesAggregator()
    tx_hex = '0x0582a0db79de3fa21d3b92a8658e0b1034c51ea54a8e06ea84fbb91d41b8fe17'
    evmhash = deserialize_evm_tx_hash(tx_hex)
    transaction = EthereumTransaction(
        tx_hash=evmhash,
        timestamp=1646375440,
        block_number=14351442,
        from_address='0xc931De6d845846E332a52D045072E3feF540Bd5d',
        to_address='0xE295aD71242373C37C5FdA7B57F26f9eA1088AFe',
        value=0,
        gas=171249,
        gas_price=22990000000,
        gas_used=171249,
        input_data=hexstring_to_bytes('0x2e7ba6ef000000000000000000000000000000000000000000000000000000000000c0e5000000000000000000000000c931de6d845846e332a52d045072e3fef540bd5d00000000000000000000000000000000000000000000002109156970b0a5f32f00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000010dbe83b35ea054d18e5fdd804d60b6a528f4b66a227079ecb82febf8eb40919495d102f8922e57278b2b6bb3369ae34c37c378dbd4819126c5e5d371ed4777c4580a9985219f50d16cefc798c2aeb6a4d7fa786f4f38ab27b420e6f3f8e25bd0f45709afe1f9fdec3cbea17d1ec63c6f62ce396524b04c9460bb05ef548239ae050b5330a4228c26b8b25ff021c6cc89ed4f0411ecce80256d090d860f9e6ff5e604076af74bd91959259ff59f8d54455a0edcad41ef1fe230504826f025769c250d89c63241d1dfec9dc4dc75f0a0ec47bcc10594ca7db74335507a5f6e4344b52b129d8e0aaeffe22b7595fa9f11c8e2381feafaf25042407913b9ec34cdf879a05d18a68b7a2506a29ba42fb004c7f32390f986f943a2557e304dc777f73869a046dc08506268e16603452a33ea179b4932eeae59338dd3fee75685cc490f1acba6c0ed0c90792bb6f9f696ad1417efe0032bb0e86b6927234ce419628e24c0d577b40b8956166e4d21cba88b58b32dec0a00b2864e8ed4ac5d7be6683f5f297aaf35d6ca208a954554f4ab14a1ca973daf13e7c1dad49db82611f4dadf2a3c32355753f5e11ba88adc0d27f10ad32ad4904bfd782c15693c6795b047124fccd0f927a7dda89206be7ad613644d02a622c3f30f5de40d052b4c3e10ef02a18107e7a23a7abca2aacc0bf854e247569f822013a86927b10f772b7b13fbc8732'),  # noqa: E501
        nonce=19,
    )
    receipt = EthereumTxReceipt(
        tx_hash=evmhash,
        contract_address=None,
        status=True,
        type=0,
        logs=[
            EthereumTxReceiptLog(
                log_index=297,
                data=hexstring_to_bytes('0x00000000000000000000000000000000000000000000002109156970b0a5f32f'),  # noqa: E501
                address=string_to_ethereum_address('0x111111111117dC0aa78b770fA6A738034120C302'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000e295ad71242373c37c5fda7b57f26f9ea1088afe'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000c931de6d845846e332a52d045072e3fef540bd5d'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=298,
                data=hexstring_to_bytes('0x000000000000000000000000000000000000000000000000000000000000c0e5000000000000000000000000c931de6d845846e332a52d045072e3fef540bd5d00000000000000000000000000000000000000000000002109156970b0a5f32f'),  # noqa: E501
                address=string_to_ethereum_address('0xE295aD71242373C37C5FdA7B57F26f9eA1088AFe'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0x4ec90e965519d92681267467f775ada5bd214aa92c0dc93d90a5e880ce9ed026'),  # noqa: E501
                ],
            ),
        ],
    )

    dbethtx = DBEthTx(database)
    dbethtx.add_ethereum_transactions([transaction], relevant_address=None)
    decoder = EVMTransactionDecoder(
        database=database,
        ethereum_manager=ethereum_manager,
        eth_transactions=eth_transactions,
        msg_aggregator=msg_aggregator,
    )
    events = decoder.decode_transaction(transaction=transaction, tx_receipt=receipt)
    assert len(events) == 2
    expected_events = [
        HistoryBaseEntry(
            event_identifier='0x0582a0db79de3fa21d3b92a8658e0b1034c51ea54a8e06ea84fbb91d41b8fe17',
            sequence_index=0,
            timestamp=1646375440000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.FEE,
            asset=A_ETH,
            balance=Balance(
                amount=FVal(0.00393701451),
                usd_value=ZERO,
            ),
            location_label='0xc931De6d845846E332a52D045072E3feF540Bd5d',
            notes='Burned 0.00393701451 ETH in gas from 0xc931De6d845846E332a52D045072E3feF540Bd5d',  # noqa: E501
            counterparty=CPT_GAS,
        ), HistoryBaseEntry(
            event_identifier='0x0582a0db79de3fa21d3b92a8658e0b1034c51ea54a8e06ea84fbb91d41b8fe17',
            sequence_index=298,
            timestamp=1646375440000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.RECEIVE,
            event_subtype=HistoryEventSubType.AIRDROP,
            asset=EthereumToken('0x111111111117dC0aa78b770fA6A738034120C302'),
            balance=Balance(amount=FVal('609.397099685988397871'), usd_value=ZERO),
            location_label='0xc931De6d845846E332a52D045072E3feF540Bd5d',
            notes='Claim 609.397099685988397871 1INCH from the 1INCH airdrop',
            counterparty=CPT_ONEINCH,
        ),
    ]
    assert events == expected_events
예제 #18
0
def test_query_transactions_removed_address(
    rotkehlchen_api_server,
    ethereum_accounts,
):
    """Make sure that if an address is removed so are the transactions from the DB"""
    start_ts = 0
    end_ts = 1598453214
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen
    db = rotki.data.db
    transactions = [
        EthereumTransaction(
            tx_hash=b'1',
            timestamp=0,
            block_number=0,
            from_address=ethereum_accounts[0],
            to_address=make_ethereum_address(),
            value=1,
            gas=1,
            gas_price=1,
            gas_used=1,
            input_data=b'',
            nonce=0,
        ),
        EthereumTransaction(
            tx_hash=b'2',
            timestamp=0,
            block_number=0,
            from_address=ethereum_accounts[0],
            to_address=make_ethereum_address(),
            value=1,
            gas=1,
            gas_price=1,
            gas_used=1,
            input_data=b'',
            nonce=1,
        ),
        EthereumTransaction(  # should remain after deletining account[0]
            tx_hash=b'3',
            timestamp=0,
            block_number=0,
            from_address=make_ethereum_address(),
            to_address=ethereum_accounts[1],
            value=1,
            gas=1,
            gas_price=1,
            gas_used=1,
            input_data=b'',
            nonce=55,
        ),
        EthereumTransaction(  # should remain after deletining account[0]
            tx_hash=b'4',
            timestamp=0,
            block_number=0,
            from_address=ethereum_accounts[1],
            to_address=ethereum_accounts[0],
            value=1,
            gas=1,
            gas_price=1,
            gas_used=1,
            input_data=b'',
            nonce=0,
        ),
        EthereumTransaction(  # should remain after deletining account[0]
            tx_hash=b'5',
            timestamp=0,
            block_number=0,
            from_address=ethereum_accounts[0],
            to_address=ethereum_accounts[1],
            value=1,
            gas=1,
            gas_price=1,
            gas_used=1,
            input_data=b'',
            nonce=0,
        )
    ]
    dbethtx = DBEthTx(db)
    dbethtx.add_ethereum_transactions(transactions)
    # Also make sure to update query ranges so as not to query etherscan at all
    for address in ethereum_accounts:
        DBQueryRanges(db).update_used_query_range(
            location_string=f'ethtxs_{address}',
            start_ts=start_ts,
            end_ts=end_ts,
            ranges_to_query=[],
        )

    # Now remove the first account (do the mocking to not query etherscan for balances)
    setup = setup_balances(
        rotki,
        ethereum_accounts=ethereum_accounts,
        btc_accounts=[],
        eth_balances=['10000', '10000'],
    )
    with ExitStack() as stack:
        setup.enter_ethereum_patches(stack)
        response = requests.delete(api_url_for(
            rotkehlchen_api_server,
            "blockchainsaccountsresource",
            blockchain='ETH',
        ),
                                   json={'accounts': [ethereum_accounts[0]]})
    assert_proper_response_with_result(response)

    # Check that only the 3 remanining transactions from the other account is returned
    response = requests.get(
        api_url_for(
            rotkehlchen_api_server,
            'ethereumtransactionsresource',
        ), )
    result = assert_proper_response_with_result(response)
    assert len(result['entries']) == 3
    assert result['entries_found'] == 3
예제 #19
0
def test_pickle_withdraw(database, ethereum_manager, eth_transactions):
    """Data for withdraw taken from
    https://etherscan.io/tx/0x91bc102e1cbb0e4542a10a7a13370b5e591d8d284989bdb0ca4ece4e54e61bab
    """
    msg_aggregator = MessagesAggregator()
    tx_hex = '0x91bc102e1cbb0e4542a10a7a13370b5e591d8d284989bdb0ca4ece4e54e61bab'
    evmhash = deserialize_evm_tx_hash(tx_hex)
    transaction = EthereumTransaction(
        tx_hash=evmhash,
        timestamp=1646375440,
        block_number=14355951,
        from_address='0xC7Dc4Cd171812a441A30472219d390f4F15f6070',
        to_address='0xb4EBc2C371182DeEa04B2264B9ff5AC4F0159C69',
        value=0,
        gas=171249,
        gas_price=22990000000,
        gas_used=171249,
        input_data=hexstring_to_bytes('0x853828b6'),  # noqa: E501
        nonce=23,
    )
    receipt = EthereumTxReceipt(
        tx_hash=evmhash,
        contract_address=None,
        status=True,
        type=0,
        logs=[
            EthereumTxReceiptLog(
                log_index=105,
                data=hexstring_to_bytes('0x00000000000000000000000000000000000000000000000d4f4e1608c485628b'),  # noqa: E501
                address=string_to_ethereum_address('0xb4EBc2C371182DeEa04B2264B9ff5AC4F0159C69'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000c7dc4cd171812a441a30472219d390f4f15f6070'),  # noqa: E501
                    hexstring_to_bytes('0x0000000000000000000000000000000000000000000000000000000000000000'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=106,
                data=hexstring_to_bytes('0x000000000000000000000000000000000000000000000015da18947013228f17'),  # noqa: E501
                address=string_to_ethereum_address('0xf4d2888d29D722226FafA5d9B24F9164c092421E'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000b4ebc2c371182deea04b2264b9ff5ac4f0159c69'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000c7dc4cd171812a441a30472219d390f4f15f6070'),  # noqa: E501
                ],
            ),
        ],
    )

    dbethtx = DBEthTx(database)
    dbethtx.add_ethereum_transactions([transaction], relevant_address=None)
    decoder = EVMTransactionDecoder(
        database=database,
        ethereum_manager=ethereum_manager,
        eth_transactions=eth_transactions,
        msg_aggregator=msg_aggregator,
    )
    events = decoder.decode_transaction(transaction=transaction, tx_receipt=receipt)
    assert len(events) == 3
    expected_events = [
        HistoryBaseEntry(
            event_identifier='0x91bc102e1cbb0e4542a10a7a13370b5e591d8d284989bdb0ca4ece4e54e61bab',
            sequence_index=0,
            timestamp=1646375440000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.FEE,
            asset=A_ETH,
            balance=Balance(
                amount=FVal(0.00393701451),
                usd_value=ZERO,
            ),
            location_label='0xC7Dc4Cd171812a441A30472219d390f4F15f6070',
            notes='Burned 0.00393701451 ETH in gas from 0xC7Dc4Cd171812a441A30472219d390f4F15f6070',  # noqa: E501
            counterparty=CPT_GAS,
        ), HistoryBaseEntry(
            event_identifier='0x91bc102e1cbb0e4542a10a7a13370b5e591d8d284989bdb0ca4ece4e54e61bab',
            sequence_index=106,
            timestamp=1646375440000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.RETURN_WRAPPED,
            asset=EthereumToken('0xb4EBc2C371182DeEa04B2264B9ff5AC4F0159C69'),
            balance=Balance(amount=FVal('245.522202162316534411'), usd_value=ZERO),
            location_label='0xC7Dc4Cd171812a441A30472219d390f4F15f6070',
            notes='Return 245.522202162316534411 pLOOKS to the pickle contract',
            counterparty='pickle finance',
        ), HistoryBaseEntry(
            event_identifier='0x91bc102e1cbb0e4542a10a7a13370b5e591d8d284989bdb0ca4ece4e54e61bab',
            sequence_index=107,
            timestamp=1646375440000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.WITHDRAWAL,
            event_subtype=HistoryEventSubType.REMOVE_ASSET,
            asset=EthereumToken('0xf4d2888d29D722226FafA5d9B24F9164c092421E'),
            balance=Balance(amount=FVal('403.097099656688209687'), usd_value=ZERO),
            location_label='0xC7Dc4Cd171812a441A30472219d390f4F15f6070',
            notes='Unstake 403.097099656688209687 LOOKS from the pickle contract',
            counterparty='pickle finance',
        )]
    assert events == expected_events
예제 #20
0
def test_curve_remove_imbalanced(database, ethereum_manager, eth_transactions):
    """Data for deposit taken from
    https://etherscan.io/tx/0xd8832abcf4773abe24d8cda5581fb53bfb3850c535c1956d1d120a72a4ebcbd8
    This tests uses the steth pool to verify that withdrawals are correctly decoded when an
    internal transaction is made for eth transfers
    """
    msg_aggregator = MessagesAggregator()
    tx_hex = '0xd8832abcf4773abe24d8cda5581fb53bfb3850c535c1956d1d120a72a4ebcbd8'
    location_label = '0x2fac74A3a04B031F240923621a578724C40678af'
    evmhash = deserialize_evm_tx_hash(tx_hex)
    transaction = EthereumTransaction(
        tx_hash=evmhash,
        timestamp=1650276061,
        block_number=14647221,
        from_address=location_label,
        to_address='0xbBC81d23Ea2c3ec7e56D39296F0cbB648873a5d3',
        value=0,
        gas=171249,
        gas_price=22990000000,
        gas_used=171249,
        input_data=hexstring_to_bytes('0x517a55a300000000000000000000000000000000000000000000001fa9ee7266a543831f00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000003f487c50000000000000000000000000000000000000000000000000000000000000001'),  # noqa: E501
        nonce=5,
    )
    receipt = EthereumTxReceipt(
        tx_hash=evmhash,
        contract_address=None,
        status=True,
        type=0,
        logs=[
            EthereumTxReceiptLog(
                log_index=2183,
                data=hexstring_to_bytes('0x00000000000000000000000000000000000000000000001fa9ee7266a543831f'),  # noqa: E501
                address=string_to_ethereum_address('0xdF5e0e81Dff6FAF3A7e52BA697820c5e32D806A8'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x0000000000000000000000002fac74a3a04b031f240923621a578724c40678af'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000bbc81d23ea2c3ec7e56d39296f0cbb648873a5d3'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=2184,
                data=hexstring_to_bytes('0x0000000000000000000000000000000000000000000000000000000000000000'),  # noqa: E501
                address=string_to_ethereum_address('0x16de59092dAE5CcF4A1E6439D611fd0653f0Bd01'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x00000000000000000000000045f783cce6b7ff23b2ab2d70e416cdb7d6055f51'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000bbc81d23ea2c3ec7e56d39296f0cbb648873a5d3'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=2185,
                data=hexstring_to_bytes('0x000000000000000000000000000000000000000000000000000000001fdb750a'),  # noqa: E501
                address=string_to_ethereum_address('0xd6aD7a6750A7593E092a9B218d66C0A814a3436e'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x00000000000000000000000045f783cce6b7ff23b2ab2d70e416cdb7d6055f51'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000bbc81d23ea2c3ec7e56d39296f0cbb648873a5d3'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=2186,
                data=hexstring_to_bytes('0x0000000000000000000000000000000000000000000000000000000000000000'),  # noqa: E501
                address=string_to_ethereum_address('0x83f798e925BcD4017Eb265844FDDAbb448f1707D'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x00000000000000000000000045f783cce6b7ff23b2ab2d70e416cdb7d6055f51'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000bbc81d23ea2c3ec7e56d39296f0cbb648873a5d3'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=2187,
                data=hexstring_to_bytes('0x0000000000000000000000000000000000000000000000000000000000000000'),  # noqa: E501
                address=string_to_ethereum_address('0x73a052500105205d34Daf004eAb301916DA8190f'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x00000000000000000000000045f783cce6b7ff23b2ab2d70e416cdb7d6055f51'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000bbc81d23ea2c3ec7e56d39296f0cbb648873a5d3'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=2188,
                data=hexstring_to_bytes('0x0000000000000000000000000000000000000000000000000000000000000000'),  # noqa: E501
                address=string_to_ethereum_address('0xdF5e0e81Dff6FAF3A7e52BA697820c5e32D806A8'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000bbc81d23ea2c3ec7e56d39296f0cbb648873a5d3'),  # noqa: E501
                    hexstring_to_bytes('0x0000000000000000000000000000000000000000000000000000000000000000'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=2189,
                data=hexstring_to_bytes('0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001fdb750a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045cf4bec2e53f0000000000000000000000000000000000000000000000000000000000000e07e000000000000000000000000000000000000000000000000000000000000570d0000000000000000000000000000000000000000000000000051077d9dc293100000000000000000000000000000000000000000000c740195f187122987a9ef0000000000000000000000000000000000000000000aeddccb3976328f7d90bd'),  # noqa: E501
                address=string_to_ethereum_address('0x45F783CCE6B7FF23B2ab2D70e416cdb7D6055f51'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xb964b72f73f5ef5bf0fdc559b2fab9a7b12a39e47817a547f1f0aee47febd602'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000bbc81d23ea2c3ec7e56d39296f0cbb648873a5d3'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000bbc81d23ea2c3ec7e56d39296f0cbb648873a5d3'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=2189,
                data=hexstring_to_bytes('0x0000000000000000000000000000000000000000000000000000000027a72df9'),  # noqa: E501
                address=string_to_ethereum_address('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000bbc81d23ea2c3ec7e56d39296f0cbb648873a5d3'),  # noqa: E501
                    hexstring_to_bytes('0x0000000000000000000000002fac74a3a04b031f240923621a578724c40678af'),  # noqa: E501
                ],
            ),
        ],
    )
    dbethtx = DBEthTx(database)
    dbethtx.add_ethereum_transactions([transaction], relevant_address=None)
    decoder = EVMTransactionDecoder(
        database=database,
        ethereum_manager=ethereum_manager,
        eth_transactions=eth_transactions,
        msg_aggregator=msg_aggregator,
    )
    events = decoder.decode_transaction(transaction=transaction, tx_receipt=receipt)
    expected_events = [
        HistoryBaseEntry(
            event_identifier=tx_hex,
            sequence_index=0,
            timestamp=1650276061000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.FEE,
            asset=A_ETH,
            balance=Balance(
                amount=FVal(0.00393701451),
                usd_value=ZERO,
            ),
            location_label=location_label,
            notes='Burned 0.00393701451 ETH in gas from 0x2fac74A3a04B031F240923621a578724C40678af',  # noqa: E501
            counterparty=CPT_GAS,
        ), HistoryBaseEntry(
            event_identifier=tx_hex,
            sequence_index=2184,
            timestamp=1650276061000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.RETURN_WRAPPED,
            asset=EthereumToken('0xdF5e0e81Dff6FAF3A7e52BA697820c5e32D806A8'),
            balance=Balance(amount=FVal('584.093916507047953183'), usd_value=ZERO),
            location_label=location_label,
            notes='Return 584.093916507047953183 yDAI+yUSDC+yUSDT+yTUSD',
            counterparty=CPT_CURVE,
        ), HistoryBaseEntry(
            event_identifier=tx_hex,
            sequence_index=2190,
            timestamp=1650276061000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.WITHDRAWAL,
            event_subtype=HistoryEventSubType.REMOVE_ASSET,
            asset=A_USDC,
            balance=Balance(amount=FVal('665.267705'), usd_value=ZERO),
            location_label=location_label,
            notes='Receive 665.267705 USDC from the curve pool 0xbBC81d23Ea2c3ec7e56D39296F0cbB648873a5d3',  # noqa: E501
            counterparty=CPT_CURVE,
        )]
    assert expected_events == events
예제 #21
0
def test_curve_remove_liquidity_with_internal(database, ethereum_manager, eth_transactions):
    """Data for deposit taken from
    https://etherscan.io/tx/0x30bb99f3e34fb1fbcf009320af7e290caf18b04b207319e15aa8ffbf645f4ad9
    This tests uses the steth pool to verify that withdrawals are correctly decoded when an
    internal transaction is made for eth transfers
    """
    msg_aggregator = MessagesAggregator()
    tx_hex = '0x30bb99f3e34fb1fbcf009320af7e290caf18b04b207319e15aa8ffbf645f4ad9'
    location_label = '0xa8005630caE7b7d2AFADD38FD3B3040d13cbE2BC'
    evmhash = deserialize_evm_tx_hash(tx_hex)
    transaction = EthereumTransaction(
        tx_hash=evmhash,
        timestamp=1650276061,
        block_number=14647221,
        from_address=location_label,
        to_address='0xF178C0b5Bb7e7aBF4e12A4838C7b7c5bA2C623c0',
        value=0,
        gas=171249,
        gas_price=22990000000,
        gas_used=171249,
        input_data=hexstring_to_bytes('0x1a4d01d20000000000000000000000000000000000000000000000a8815561fefbe56aa300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a8d15fc942541fea7f'),  # noqa: E501
        nonce=5,
    )
    receipt = EthereumTxReceipt(
        tx_hash=evmhash,
        contract_address=None,
        status=True,
        type=0,
        logs=[
            EthereumTxReceiptLog(
                log_index=191,
                data=hexstring_to_bytes('0x0000000000000000000000000000000000000000000000000dc335d474901e08'),  # noqa: E501
                address=string_to_ethereum_address('0x06325440D014e39736583c165C2963BA99fAf14E'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000a8005630cae7b7d2afadd38fd3b3040d13cbe2bc'),  # noqa: E501
                    hexstring_to_bytes('0x0000000000000000000000000000000000000000000000000000000000000000'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=192,
                data=hexstring_to_bytes('0x0000000000000000000000000000000000000000000000000dc335d474901e080000000000000000000000000000000000000000000000000e48d018621788fa'),  # noqa: E501
                address=string_to_ethereum_address('0xDC24316b9AE028F1497c275EB9192a3Ea0f67022'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0x9e96dd3b997a2a257eec4df9bb6eaf626e206df5f543bd963682d143300be310'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000a8005630cae7b7d2afadd38fd3b3040d13cbe2bc'),  # noqa: E501
                ],
            ),
        ],
    )
    internal_tx = EthereumInternalTransaction(
        parent_tx_hash=evmhash,
        trace_id=27,
        timestamp=Timestamp(1591043988),
        block_number=14647221,
        from_address='0xDC24316b9AE028F1497c275EB9192a3Ea0f67022',
        to_address='0xa8005630caE7b7d2AFADD38FD3B3040d13cbE2BC',
        value=FVal('1.02930131799766041') * EXP18,
    )
    dbethtx = DBEthTx(database)
    dbethtx.add_ethereum_transactions([transaction], relevant_address=None)
    dbethtx.add_ethereum_internal_transactions([internal_tx], relevant_address=location_label)  # noqa: E501
    decoder = EVMTransactionDecoder(
        database=database,
        ethereum_manager=ethereum_manager,
        eth_transactions=eth_transactions,
        msg_aggregator=msg_aggregator,
    )
    events = decoder.decode_transaction(transaction=transaction, tx_receipt=receipt)
    expected_events = [
        HistoryBaseEntry(
            event_identifier=tx_hex,
            sequence_index=0,
            timestamp=1650276061000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.FEE,
            asset=A_ETH,
            balance=Balance(
                amount=FVal(0.00393701451),
                usd_value=ZERO,
            ),
            location_label=location_label,
            notes='Burned 0.00393701451 ETH in gas from 0xa8005630caE7b7d2AFADD38FD3B3040d13cbE2BC',  # noqa: E501
            counterparty=CPT_GAS,
        ), HistoryBaseEntry(
            event_identifier=tx_hex,
            sequence_index=1,
            timestamp=1650276061000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.WITHDRAWAL,
            event_subtype=HistoryEventSubType.REMOVE_ASSET,
            asset=A_ETH,
            balance=Balance(amount=FVal('1.02930131799766041'), usd_value=ZERO),
            location_label=location_label,
            notes='Remove 1.02930131799766041 ETH from the curve pool',
            counterparty=CPT_CURVE,
        ), HistoryBaseEntry(
            event_identifier=tx_hex,
            sequence_index=193,
            timestamp=1650276061000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.RETURN_WRAPPED,
            asset=EthereumToken('0x06325440D014e39736583c165C2963BA99fAf14E'),
            balance=Balance(amount=FVal('0.991695529556581896'), usd_value=ZERO),
            location_label=location_label,
            notes='Return 0.991695529556581896 steCRV',
            counterparty=CPT_CURVE,
        )]
    assert expected_events == events
예제 #22
0
def test_curve_remove_liquidity(database, ethereum_manager, eth_transactions):
    """Data for deposit taken from
    https://etherscan.io/tx/0xd63dccdbebeede3a1f50b97c0a8592255203a0559880b80377daa39f915741b0
    This tests uses the link pool to verify that withdrawals are correctly decoded
    """
    msg_aggregator = MessagesAggregator()
    tx_hex = '0xd63dccdbebeede3a1f50b97c0a8592255203a0559880b80377daa39f915741b0'
    location_label = '0xDf9f0AE722A3919fE7f9cC8805773ef142007Ca6'
    evmhash = deserialize_evm_tx_hash(tx_hex)
    transaction = EthereumTransaction(
        tx_hash=evmhash,
        timestamp=1650276061,
        block_number=14608535,
        from_address=location_label,
        to_address='0xF178C0b5Bb7e7aBF4e12A4838C7b7c5bA2C623c0',
        value=0,
        gas=171249,
        gas_price=22990000000,
        gas_used=171249,
        input_data=hexstring_to_bytes('0x1a4d01d20000000000000000000000000000000000000000000000a8815561fefbe56aa300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a8d15fc942541fea7f'),  # noqa: E501
        nonce=5,
    )
    receipt = EthereumTxReceipt(
        tx_hash=evmhash,
        contract_address=None,
        status=True,
        type=0,
        logs=[
            EthereumTxReceiptLog(
                log_index=506,
                data=hexstring_to_bytes('0x0000000000000000000000000000000000000000000000a8815561fefbe56aa3'),  # noqa: E501
                address=string_to_ethereum_address('0xcee60cFa923170e4f8204AE08B4fA6A3F5656F3a'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000df9f0ae722a3919fe7f9cc8805773ef142007ca6'),  # noqa: E501
                    hexstring_to_bytes('0x0000000000000000000000000000000000000000000000000000000000000000'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=507,
                data=hexstring_to_bytes('0000000000000000000000000000000000000000000000a93078ae269dbeca10'),  # noqa: E501
                address=string_to_ethereum_address('0x514910771AF9Ca656af840dff83E8264EcF986CA'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000f178c0b5bb7e7abf4e12a4838c7b7c5ba2c623c0'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000df9f0ae722a3919fe7f9cc8805773ef142007ca6'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=508,
                data=hexstring_to_bytes('0x0000000000000000000000000000000000000000000000a8815561fefbe56aa30000000000000000000000000000000000000000000000a93078ae269dbeca100000000000000000000000000000000000000000000092c009040e68c381c519'),  # noqa: E501
                address=string_to_ethereum_address('0xF178C0b5Bb7e7aBF4e12A4838C7b7c5bA2C623c0'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0x5ad056f2e28a8cec232015406b843668c1e36cda598127ec3b8c59b8c72773a0'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000df9f0ae722a3919fe7f9cc8805773ef142007ca6'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=415,
                data=hexstring_to_bytes('0x00000000000000000000000000000000000000000000000002c68af0bb14000000000000000000000000000000000000000000000000000002c6526ca273a80000000000000000000000000000000000000000000000000000000016a92ed4ce00000000000000000000000000000000000000000000000000000016a9b386830000000000000000000000000000000000000000000156e4db21d9cf6a6d4f3f000000000000000000000000000000000000000000014a4959a6fb2bf53a7108'),  # noqa: E501
                address=string_to_ethereum_address('0xDC24316b9AE028F1497c275EB9192a3Ea0f67022'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0x26f55a85081d24974e85c6c00045d0f0453991e95873f52bff0d21af4079a768'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000767b35b9f06f6e28e5ed05ee7c27bdf992eba5d2'),  # noqa: E501
                ],
            ),
        ],
    )

    dbethtx = DBEthTx(database)
    dbethtx.add_ethereum_transactions([transaction], relevant_address=None)
    decoder = EVMTransactionDecoder(
        database=database,
        ethereum_manager=ethereum_manager,
        eth_transactions=eth_transactions,
        msg_aggregator=msg_aggregator,
    )
    events = decoder.decode_transaction(transaction=transaction, tx_receipt=receipt)
    expected_events = [
        HistoryBaseEntry(
            event_identifier=tx_hex,
            sequence_index=0,
            timestamp=1650276061000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.FEE,
            asset=A_ETH,
            balance=Balance(
                amount=FVal(0.00393701451),
                usd_value=ZERO,
            ),
            location_label=location_label,
            notes='Burned 0.00393701451 ETH in gas from 0xDf9f0AE722A3919fE7f9cC8805773ef142007Ca6',  # noqa: E501
            counterparty=CPT_GAS,
        ), HistoryBaseEntry(
            event_identifier=tx_hex,
            sequence_index=507,
            timestamp=1650276061000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.RETURN_WRAPPED,
            asset=EthereumToken('0xcee60cFa923170e4f8204AE08B4fA6A3F5656F3a'),
            balance=Balance(amount=FVal('3108.372467134893484707'), usd_value=ZERO),
            location_label=location_label,
            notes='Return 3108.372467134893484707 linkCRV',
            counterparty=CPT_CURVE,
        ), HistoryBaseEntry(
            event_identifier=tx_hex,
            sequence_index=508,
            timestamp=1650276061000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.WITHDRAWAL,
            event_subtype=HistoryEventSubType.REMOVE_ASSET,
            asset=A_LINK,
            balance=Balance(amount=FVal('3120.992481448818559504'), usd_value=ZERO),
            location_label=location_label,
            notes='Remove 3120.992481448818559504 LINK from the curve pool 0xF178C0b5Bb7e7aBF4e12A4838C7b7c5bA2C623c0',  # noqa: E501
            counterparty=CPT_CURVE,
        )]
    assert expected_events == events
예제 #23
0
class EVMTransactionDecoder():
    def __init__(
        self,
        database: 'DBHandler',
        ethereum_manager: 'EthereumManager',
        eth_transactions: 'EthTransactions',
        msg_aggregator: MessagesAggregator,
    ):
        self.database = database
        self.all_counterparties: Set[str] = set()
        self.ethereum_manager = ethereum_manager
        self.eth_transactions = eth_transactions
        self.msg_aggregator = msg_aggregator
        self.dbethtx = DBEthTx(self.database)
        self.dbevents = DBHistoryEvents(self.database)
        self.base = BaseDecoderTools(database=database)
        self.event_rules = [  # rules to try for all tx receipt logs decoding
            self._maybe_decode_erc20_approve,
            self._maybe_decode_erc20_721_transfer,
            self._maybe_enrich_transfers,
            self._maybe_decode_governance,
        ]
        self.token_enricher_rules: List[Callable] = [
        ]  # enrichers to run for token transfers
        self.initialize_all_decoders()
        self.undecoded_tx_query_lock = Semaphore()

    def _recursively_initialize_decoders(
        self,
        package: Union[str, ModuleType],
    ) -> Tuple[Dict[ChecksumEthAddress, Tuple[Any, ...]], List[Callable],
               List[Callable], ]:
        if isinstance(package, str):
            package = importlib.import_module(package)
        address_results = {}
        rules_results = []
        enricher_results = []
        for _, name, is_pkg in pkgutil.walk_packages(package.__path__):
            full_name = package.__name__ + '.' + name
            if full_name == __name__:
                continue  # skip -- this is this source file

            if is_pkg:
                submodule = importlib.import_module(full_name)
                # take module name, transform it and find decoder if exists
                class_name = full_name[MODULES_PREFIX_LENGTH:].translate(
                    {ord('.'): None})
                parts = class_name.split('_')
                class_name = ''.join([x.capitalize() for x in parts])
                submodule_decoder = getattr(submodule, f'{class_name}Decoder',
                                            None)

                if submodule_decoder:
                    if class_name in self.decoders:
                        raise ModuleLoadingError(
                            f'Decoder with name {class_name} already loaded')
                    self.decoders[class_name] = submodule_decoder(
                        ethereum_manager=self.ethereum_manager,
                        base_tools=self.base,
                        msg_aggregator=self.msg_aggregator,
                    )
                    address_results.update(
                        self.decoders[class_name].addresses_to_decoders())
                    rules_results.extend(
                        self.decoders[class_name].decoding_rules())
                    enricher_results.extend(
                        self.decoders[class_name].enricher_rules())
                    self.all_counterparties.update(
                        self.decoders[class_name].counterparties())

                recursive_addrs, recursive_rules, recurisve_enricher_results = self._recursively_initialize_decoders(
                    full_name)  # noqa: E501
                address_results.update(recursive_addrs)
                rules_results.extend(recursive_rules)
                enricher_results.extend(recurisve_enricher_results)

        return address_results, rules_results, enricher_results

    def initialize_all_decoders(self) -> None:
        """Recursively check all submodules to get all decoder address mappings and rules
        """
        self.decoders: Dict[str, 'DecoderInterface'] = {}
        address_result, rules_result, enrichers_result = self._recursively_initialize_decoders(
            MODULES_PACKAGE)  # noqa: E501
        self.address_mappings = address_result
        self.event_rules.extend(rules_result)
        self.token_enricher_rules.extend(enrichers_result)
        # update with counterparties not in any module
        self.all_counterparties.update([CPT_GAS, CPT_GNOSIS_CHAIN])

    def reload_from_db(self) -> None:
        """Reload all related settings from DB so that decoding happens with latest"""
        self.base.refresh_tracked_accounts()
        for _, decoder in self.decoders.items():
            if isinstance(decoder, CustomizableDateMixin):
                decoder.reload_settings()

    def try_all_rules(
        self,
        token: Optional[EthereumToken],
        tx_log: EthereumTxReceiptLog,
        transaction: EthereumTransaction,
        decoded_events: List[HistoryBaseEntry],
        action_items: List[ActionItem],
    ) -> Optional[HistoryBaseEntry]:
        for rule in self.event_rules:
            event = rule(token=token,
                         tx_log=tx_log,
                         transaction=transaction,
                         decoded_events=decoded_events,
                         action_items=action_items)  # noqa: E501
            if event:
                return event

        return None

    def decode_by_address_rules(
        self,
        tx_log: EthereumTxReceiptLog,
        transaction: EthereumTransaction,
        decoded_events: List[HistoryBaseEntry],
        all_logs: List[EthereumTxReceiptLog],
        action_items: List[ActionItem],
    ) -> Tuple[Optional[HistoryBaseEntry], Optional[ActionItem]]:
        """
        Sees if the log is on an address for which we have specific decoders and calls it

        Should catch all underlying errors these decoders will raise. So far known are:
        - DeserializationError
        - ConversionError
        - UnknownAsset
        """
        mapping_result = self.address_mappings.get(tx_log.address)
        if mapping_result is None:
            return None, None
        method = mapping_result[0]

        try:
            if len(mapping_result) == 1:
                result = method(tx_log, transaction, decoded_events, all_logs,
                                action_items)
            else:
                result = method(tx_log, transaction, decoded_events, all_logs,
                                action_items,
                                *mapping_result[1:])  # noqa: E501
        except (DeserializationError, ConversionError, UnknownAsset) as e:
            log.debug(
                f'Decoding tx log with index {tx_log.log_index} of transaction '
                f'{transaction.tx_hash.hex()} through {method.__name__} failed due to {str(e)}'
            )
            return None, None

        return result

    def decode_transaction(
        self,
        transaction: EthereumTransaction,
        tx_receipt: EthereumTxReceipt,
    ) -> List[HistoryBaseEntry]:
        """Decodes an ethereum transaction and its receipt and saves result in the DB"""
        cursor = self.database.conn.cursor()
        self.base.reset_sequence_counter()
        # check if any eth transfer happened in the transaction, including in internal transactions
        events = self._maybe_decode_simple_transactions(
            transaction, tx_receipt)
        action_items: List[ActionItem] = []

        # decode transaction logs from the receipt
        for tx_log in tx_receipt.logs:
            event, action_item = self.decode_by_address_rules(
                tx_log, transaction, events, tx_receipt.logs,
                action_items)  # noqa: E501
            if action_item:
                action_items.append(action_item)
            if event:
                events.append(event)
                continue

            token = GlobalDBHandler.get_ethereum_token(tx_log.address)
            event = self.try_all_rules(token=token,
                                       tx_log=tx_log,
                                       transaction=transaction,
                                       decoded_events=events,
                                       action_items=action_items)  # noqa: E501
            if event:
                events.append(event)

        self.dbevents.add_history_events(events)
        cursor.execute(
            'INSERT OR IGNORE INTO evm_tx_mappings(tx_hash, blockchain, value) VALUES(?, ?, ?)',
            (transaction.tx_hash, 'ETH', HISTORY_MAPPING_DECODED),
        )
        self.database.update_last_write()
        return sorted(events, key=lambda x: x.sequence_index, reverse=False)

    def get_and_decode_undecoded_transactions(self,
                                              limit: Optional[int] = None
                                              ) -> None:
        """Checks the DB for up to `limit` undecoded transactions and decodes them.

        This is protected by concurrent access from a lock"""
        with self.undecoded_tx_query_lock:
            hashes = self.dbethtx.get_transaction_hashes_not_decoded(
                limit=limit)
            self.decode_transaction_hashes(ignore_cache=False,
                                           tx_hashes=hashes)

    def decode_transaction_hashes(
        self, ignore_cache: bool, tx_hashes: Optional[List[EVMTxHash]]
    ) -> List[HistoryBaseEntry]:  # noqa: E501
        """Make sure that receipts are pulled + events decoded for the given transaction hashes.

        The transaction hashes must exist in the DB at the time of the call

        May raise:
        - DeserializationError if there is a problem with conacting a remote to get receipts
        - RemoteError if there is a problem with contacting a remote to get receipts
        - InputError if the transaction hash is not found in the DB
        """
        events = []
        self.reload_from_db()

        # If no transaction hashes are passed, decode all transactions.
        if tx_hashes is None:
            tx_hashes = []
            cursor = self.database.conn.cursor()
            for entry in cursor.execute(
                    'SELECT tx_hash FROM ethereum_transactions'):
                tx_hashes.append(EVMTxHash(entry[0]))

        for tx_hash in tx_hashes:
            try:
                receipt = self.eth_transactions.get_or_query_transaction_receipt(
                    tx_hash)
            except RemoteError as e:
                raise InputError(
                    f'Hash {tx_hash.hex()} does not correspond to a transaction'
                ) from e  # noqa: E501

            # TODO: Change this if transaction filter query can accept multiple hashes
            txs = self.dbethtx.get_ethereum_transactions(
                filter_=ETHTransactionsFilterQuery.make(tx_hash=tx_hash),
                has_premium=True,  # ignore limiting here
            )
            events.extend(
                self.get_or_decode_transaction_events(
                    transaction=txs[0],
                    tx_receipt=receipt,
                    ignore_cache=ignore_cache,
                ))

        return events

    def get_or_decode_transaction_events(
        self,
        transaction: EthereumTransaction,
        tx_receipt: EthereumTxReceipt,
        ignore_cache: bool,
    ) -> List[HistoryBaseEntry]:
        """Get a transaction's events if existing in the DB or decode them"""
        cursor = self.database.conn.cursor()
        if ignore_cache is True:  # delete all decoded events
            self.dbevents.delete_events_by_tx_hash([transaction.tx_hash])
            cursor.execute(
                'DELETE from evm_tx_mappings WHERE tx_hash=? AND blockchain=? AND value=?',
                (transaction.tx_hash, 'ETH', HISTORY_MAPPING_DECODED),
            )
        else:  # see if events are already decoded and return them
            results = cursor.execute(
                'SELECT COUNT(*) from evm_tx_mappings WHERE tx_hash=? AND blockchain=? AND value=?',  # noqa: E501
                (transaction.tx_hash, 'ETH', HISTORY_MAPPING_DECODED),
            )
            if results.fetchone()[0] != 0:  # already decoded and in the DB
                events = self.dbevents.get_history_events(
                    filter_query=HistoryEventFilterQuery.make(
                        event_identifier=transaction.tx_hash.hex(), ),
                    has_premium=
                    True,  # for this function we don't limit anything
                )
                return events

        # else we should decode now
        events = self.decode_transaction(transaction, tx_receipt)
        return events

    def _maybe_decode_internal_transactions(
        self,
        tx: EthereumTransaction,
        tx_receipt: EthereumTxReceipt,
        events: List[HistoryBaseEntry],
        tx_hash_hex: str,
        ts_ms: TimestampMS,
    ) -> None:
        """
        check for internal transactions if the transaction is not canceled. This function mutates
        the events argument.
        """
        if tx_receipt.status is False:
            return

        internal_txs = self.dbethtx.get_ethereum_internal_transactions(
            parent_tx_hash=tx.tx_hash, )
        for internal_tx in internal_txs:
            if internal_tx.to_address is None:
                continue  # can that happen? Internal transaction deploying a contract?
            direction_result = self.base.decode_direction(
                internal_tx.from_address, internal_tx.to_address)  # noqa: E501
            if direction_result is None:
                continue

            amount = ZERO if internal_tx.value == 0 else from_wei(
                FVal(internal_tx.value))
            if amount == ZERO:
                continue

            event_type, location_label, counterparty, verb = direction_result
            events.append(
                HistoryBaseEntry(
                    event_identifier=tx_hash_hex,
                    sequence_index=self.base.get_next_sequence_counter(),
                    timestamp=ts_ms,
                    location=Location.BLOCKCHAIN,
                    location_label=location_label,
                    asset=A_ETH,
                    balance=Balance(amount=amount),
                    notes=
                    f'{verb} {amount} ETH {internal_tx.from_address} -> {internal_tx.to_address}',  # noqa: E501
                    event_type=event_type,
                    event_subtype=HistoryEventSubType.NONE,
                    counterparty=counterparty,
                ))

    def _maybe_decode_simple_transactions(
        self,
        tx: EthereumTransaction,
        tx_receipt: EthereumTxReceipt,
    ) -> List[HistoryBaseEntry]:
        """Decodes normal ETH transfers, internal transactions and gas cost payments"""
        events: List[HistoryBaseEntry] = []
        tx_hash_hex = tx.tx_hash.hex()
        ts_ms = ts_sec_to_ms(tx.timestamp)

        # check for gas spent
        direction_result = self.base.decode_direction(tx.from_address,
                                                      tx.to_address)
        if direction_result is not None:
            event_type, location_label, counterparty, verb = direction_result
            if event_type in (HistoryEventType.SPEND,
                              HistoryEventType.TRANSFER):
                eth_burned_as_gas = from_wei(FVal(tx.gas_used * tx.gas_price))
                events.append(
                    HistoryBaseEntry(
                        event_identifier=tx_hash_hex,
                        sequence_index=self.base.get_next_sequence_counter(),
                        timestamp=ts_ms,
                        location=Location.BLOCKCHAIN,
                        location_label=location_label,
                        asset=A_ETH,
                        balance=Balance(amount=eth_burned_as_gas),
                        notes=
                        f'Burned {eth_burned_as_gas} ETH in gas from {location_label}',
                        event_type=HistoryEventType.SPEND,
                        event_subtype=HistoryEventSubType.FEE,
                        counterparty=CPT_GAS,
                    ))

        # Decode internal transactions after gas so gas is always 0 indexed
        self._maybe_decode_internal_transactions(
            tx=tx,
            tx_receipt=tx_receipt,
            events=events,
            tx_hash_hex=tx_hash_hex,
            ts_ms=ts_ms,
        )

        if tx_receipt.status is False or direction_result is None:
            # Not any other action to do for failed transactions or transaction where
            # any tracked address is not involved
            return events

        # now decode the actual transaction eth transfer itself
        amount = ZERO if tx.value == 0 else from_wei(FVal(tx.value))
        if tx.to_address is None:
            if not self.base.is_tracked(tx.from_address):
                return events

            events.append(
                HistoryBaseEntry(  # contract deployment
                    event_identifier=tx_hash_hex,
                    sequence_index=self.base.get_next_sequence_counter(),
                    timestamp=ts_ms,
                    location=Location.BLOCKCHAIN,
                    location_label=tx.from_address,
                    asset=A_ETH,
                    balance=Balance(amount=amount),
                    notes='Contract deployment',
                    event_type=HistoryEventType.INFORMATIONAL,
                    event_subtype=HistoryEventSubType.DEPLOY,
                    counterparty=None,  # TODO: Find out contract address
                ))
            return events

        if amount == ZERO:
            return events

        events.append(
            HistoryBaseEntry(
                event_identifier=tx_hash_hex,
                sequence_index=self.base.get_next_sequence_counter(),
                timestamp=ts_ms,
                location=Location.BLOCKCHAIN,
                location_label=location_label,
                asset=A_ETH,
                balance=Balance(amount=amount),
                notes=
                f'{verb} {amount} ETH {tx.from_address} -> {tx.to_address}',
                event_type=event_type,
                event_subtype=HistoryEventSubType.NONE,
                counterparty=counterparty,
            ))
        return events

    def _maybe_decode_erc20_approve(
            self,
            token: Optional[EthereumToken],
            tx_log: EthereumTxReceiptLog,
            transaction: EthereumTransaction,
            decoded_events: List[HistoryBaseEntry],  # pylint: disable=unused-argument
            action_items: List[ActionItem],  # pylint: disable=unused-argument
    ) -> Optional[HistoryBaseEntry]:
        if tx_log.topics[0] != ERC20_APPROVE or token is None:
            return None

        owner_address = hex_or_bytes_to_address(tx_log.topics[1])
        spender_address = hex_or_bytes_to_address(tx_log.topics[2])

        if not any(
                self.base.is_tracked(x)
                for x in (owner_address, spender_address)):
            return None

        amount_raw = hex_or_bytes_to_int(tx_log.data)
        amount = token_normalized_value(token_amount=amount_raw, token=token)
        notes = f'Approve {amount} {token.symbol} of {owner_address} for spending by {spender_address}'  # noqa: E501
        return HistoryBaseEntry(
            event_identifier=transaction.tx_hash.hex(),
            sequence_index=self.base.get_sequence_index(tx_log),
            timestamp=ts_sec_to_ms(transaction.timestamp),
            location=Location.BLOCKCHAIN,
            location_label=owner_address,
            asset=token,
            balance=Balance(amount=amount),
            notes=notes,
            event_type=HistoryEventType.INFORMATIONAL,
            event_subtype=HistoryEventSubType.APPROVE,
            counterparty=spender_address,
        )

    def _maybe_decode_erc20_721_transfer(
        self,
        token: Optional[EthereumToken],
        tx_log: EthereumTxReceiptLog,
        transaction: EthereumTransaction,
        decoded_events: List[HistoryBaseEntry],  # pylint: disable=unused-argument
        action_items: List[ActionItem],
    ) -> Optional[HistoryBaseEntry]:
        if tx_log.topics[0] != ERC20_OR_ERC721_TRANSFER:
            return None

        if token is None:
            try:
                found_token = get_or_create_ethereum_token(
                    userdb=self.database,
                    ethereum_address=tx_log.address,
                    ethereum_manager=self.ethereum_manager,
                )
            except NotERC20Conformant:
                return None  # ignore non-ERC20 transfers for now
        else:
            found_token = token

        transfer = self.base.decode_erc20_721_transfer(
            token=found_token,
            tx_log=tx_log,
            transaction=transaction,
        )
        if transfer is None:
            return None

        for idx, action_item in enumerate(action_items):
            if action_item.asset == found_token and action_item.amount == transfer.balance.amount and action_item.from_event_type == transfer.event_type and action_item.from_event_subtype == transfer.event_subtype:  # noqa: E501
                if action_item.action == 'skip':
                    action_items.pop(idx)
                    return None

                # else atm only transform
                if action_item.to_event_type is not None:
                    transfer.event_type = action_item.to_event_type
                if action_item.to_event_subtype is not None:
                    transfer.event_subtype = action_item.to_event_subtype
                if action_item.to_notes is not None:
                    transfer.notes = action_item.to_notes
                if action_item.to_counterparty is not None:
                    transfer.counterparty = action_item.to_counterparty
                if action_item.extra_data is not None:
                    transfer.extra_data = action_item.extra_data

                if action_item.paired_event_data is not None:
                    # If there is a paired event to this, take care of the order
                    out_event = transfer
                    in_event = action_item.paired_event_data[0]
                    if action_item.paired_event_data[1] is True:
                        out_event = action_item.paired_event_data[0]
                        in_event = transfer
                    maybe_reshuffle_events(
                        out_event=out_event,
                        in_event=in_event,
                        events_list=decoded_events + [transfer],
                    )

                action_items.pop(idx)
                break  # found an action item and acted on it

        # Add additional information to transfers for different protocols
        self._enrich_protocol_tranfers(
            token=found_token,
            tx_log=tx_log,
            transaction=transaction,
            event=transfer,
            action_items=action_items,
        )
        return transfer

    def _maybe_enrich_transfers(  # pylint: disable=no-self-use
            self,
            token: Optional[EthereumToken],  # pylint: disable=unused-argument
            tx_log: EthereumTxReceiptLog,
            transaction: EthereumTransaction,  # pylint: disable=unused-argument
            decoded_events: List[HistoryBaseEntry],
            action_items: List[ActionItem],  # pylint: disable=unused-argument
    ) -> Optional[HistoryBaseEntry]:
        if tx_log.topics[
                0] == GTC_CLAIM and tx_log.address == '0xDE3e5a990bCE7fC60a6f017e7c4a95fc4939299E':  # noqa: E501
            for event in decoded_events:
                if event.asset == A_GTC and event.event_type == HistoryEventType.RECEIVE:
                    event.event_subtype = HistoryEventSubType.AIRDROP
                    event.notes = f'Claim {event.balance.amount} GTC from the GTC airdrop'
            return None

        if tx_log.topics[
                0] == ONEINCH_CLAIM and tx_log.address == '0xE295aD71242373C37C5FdA7B57F26f9eA1088AFe':  # noqa: E501
            for event in decoded_events:
                if event.asset == A_1INCH and event.event_type == HistoryEventType.RECEIVE:
                    event.event_subtype = HistoryEventSubType.AIRDROP
                    event.notes = f'Claim {event.balance.amount} 1INCH from the 1INCH airdrop'  # noqa: E501
            return None

        if tx_log.topics[
                0] == GNOSIS_CHAIN_BRIDGE_RECEIVE and tx_log.address == '0x88ad09518695c6c3712AC10a214bE5109a655671':  # noqa: E501
            for event in decoded_events:
                if event.event_type == HistoryEventType.RECEIVE:
                    # user bridged from gnosis chain
                    event.event_type = HistoryEventType.TRANSFER
                    event.event_subtype = HistoryEventSubType.BRIDGE
                    event.counterparty = CPT_GNOSIS_CHAIN
                    event.notes = (
                        f'Bridge {event.balance.amount} {event.asset.symbol} from gnosis chain'
                    )

        return None

    def _enrich_protocol_tranfers(  # pylint: disable=no-self-use
        self,
        token: EthereumToken,
        tx_log: EthereumTxReceiptLog,
        transaction: EthereumTransaction,
        event: HistoryBaseEntry,
        action_items: List[ActionItem],
    ) -> None:
        """
        Decode special transfers made by contract execution for example at the moment
        of depositing assets or withdrawing.
        It assumes that the event being decoded has been already filtered and is a
        transfer.
        """
        for enrich_call in self.token_enricher_rules:
            transfer_enriched = enrich_call(
                token=token,
                tx_log=tx_log,
                transaction=transaction,
                event=event,
                action_items=action_items,
            )
            if transfer_enriched:
                break

    def _maybe_decode_governance(  # pylint: disable=no-self-use
            self,
            token: Optional[EthereumToken],  # pylint: disable=unused-argument
            tx_log: EthereumTxReceiptLog,
            transaction: EthereumTransaction,
            decoded_events: List[HistoryBaseEntry],  # pylint: disable=unused-argument
            action_items: List[ActionItem],  # pylint: disable=unused-argument
    ) -> Optional[HistoryBaseEntry]:
        if tx_log.topics[0] == GOVERNORALPHA_PROPOSE:
            if tx_log.address == '0xDbD27635A534A3d3169Ef0498beB56Fb9c937489':
                governance_name = 'Gitcoin'
            else:
                governance_name = tx_log.address

            try:
                _, decoded_data = decode_event_data_abi_str(
                    tx_log, GOVERNORALPHA_PROPOSE_ABI)
            except DeserializationError as e:
                log.debug(
                    f'Failed to decode governor alpha event due to {str(e)}')
                return None

            proposal_id = decoded_data[0]
            proposal_text = decoded_data[8]
            notes = f'Create {governance_name} proposal {proposal_id}. {proposal_text}'
            return HistoryBaseEntry(
                event_identifier=transaction.tx_hash.hex(),
                sequence_index=self.base.get_sequence_index(tx_log),
                timestamp=ts_sec_to_ms(transaction.timestamp),
                location=Location.BLOCKCHAIN,
                location_label=transaction.from_address,
                # TODO: This should be null for proposals and other informational events
                asset=A_ETH,
                balance=Balance(),
                notes=notes,
                event_type=HistoryEventType.INFORMATIONAL,
                event_subtype=HistoryEventSubType.GOVERNANCE_PROPOSE,
                counterparty=governance_name,
            )

        return None
예제 #24
0
def test_curve_deposit_eth(database, ethereum_manager, eth_transactions):
    """Data for deposit taken from
    https://etherscan.io/tx/0x51c052c8fb60f092f98ffc3cab6340c7c5348ee3b339582feba1c17cbd97ea56
    This tests uses the steth/eth pool to verify that deposits including transfer of ETH work
    properly
    """
    msg_aggregator = MessagesAggregator()
    tx_hex = '0x51c052c8fb60f092f98ffc3cab6340c7c5348ee3b339582feba1c17cbd97ea56'
    location_label = '0x767B35b9F06F6e28e5ed05eE7C27bDf992eba5d2'
    evmhash = deserialize_evm_tx_hash(tx_hex)
    transaction = EthereumTransaction(
        tx_hash=evmhash,
        timestamp=1650276061,
        block_number=14608535,
        from_address=location_label,
        to_address='0xDC24316b9AE028F1497c275EB9192a3Ea0f67022',
        value=FVal(0.2) * EXP18,
        gas=171249,
        gas_price=22990000000,
        gas_used=171249,
        input_data=hexstring_to_bytes('0x0b4c7e4d00000000000000000000000000000000000000000000000002c68af0bb14000000000000000000000000000000000000000000000000000002c6526ca273a800000000000000000000000000000000000000000000000000054aaa619fda0c01'),  # noqa: E501
        nonce=5,
    )
    receipt = EthereumTxReceipt(
        tx_hash=evmhash,
        contract_address=None,
        status=True,
        type=0,
        logs=[
            EthereumTxReceiptLog(
                log_index=412,
                data=hexstring_to_bytes('0x00000000000000000000000000000000000000000000000002c6526ca273a800'),  # noqa: E501
                address=string_to_ethereum_address('0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000767b35b9f06f6e28e5ed05ee7c27bdf992eba5d2'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000dc24316b9ae028f1497c275eb9192a3ea0f67022'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=413,
                data=hexstring_to_bytes('0xfffffffffffffffffffffffffffffffffffffffffffffffffd39ad935d8c57ff'),  # noqa: E501
                address=string_to_ethereum_address('0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000767b35b9f06f6e28e5ed05ee7c27bdf992eba5d2'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000dc24316b9ae028f1497c275eb9192a3ea0f67022'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=414,
                data=hexstring_to_bytes('0x00000000000000000000000000000000000000000000000005589f42020a37df'),  # noqa: E501
                address=string_to_ethereum_address('0x06325440D014e39736583c165C2963BA99fAf14E'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x0000000000000000000000000000000000000000000000000000000000000000'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000767b35b9f06f6e28e5ed05ee7c27bdf992eba5d2'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=415,
                data=hexstring_to_bytes('0x00000000000000000000000000000000000000000000000002c68af0bb14000000000000000000000000000000000000000000000000000002c6526ca273a80000000000000000000000000000000000000000000000000000000016a92ed4ce00000000000000000000000000000000000000000000000000000016a9b386830000000000000000000000000000000000000000000156e4db21d9cf6a6d4f3f000000000000000000000000000000000000000000014a4959a6fb2bf53a7108'),  # noqa: E501
                address=string_to_ethereum_address('0xDC24316b9AE028F1497c275EB9192a3Ea0f67022'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0x26f55a85081d24974e85c6c00045d0f0453991e95873f52bff0d21af4079a768'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000767b35b9f06f6e28e5ed05ee7c27bdf992eba5d2'),  # noqa: E501
                ],
            ),
        ],
    )

    dbethtx = DBEthTx(database)
    dbethtx.add_ethereum_transactions([transaction], relevant_address=None)
    decoder = EVMTransactionDecoder(
        database=database,
        ethereum_manager=ethereum_manager,
        eth_transactions=eth_transactions,
        msg_aggregator=msg_aggregator,
    )
    events = decoder.decode_transaction(transaction=transaction, tx_receipt=receipt)
    expected_events = [
        HistoryBaseEntry(
            event_identifier=tx_hex,
            sequence_index=0,
            timestamp=1650276061000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.FEE,
            asset=A_ETH,
            balance=Balance(
                amount=FVal(0.00393701451),
                usd_value=ZERO,
            ),
            location_label=location_label,
            notes='Burned 0.00393701451 ETH in gas from 0x767B35b9F06F6e28e5ed05eE7C27bDf992eba5d2',  # noqa: E501
            counterparty=CPT_GAS,
        ), HistoryBaseEntry(
            event_identifier=tx_hex,
            sequence_index=1,
            timestamp=1650276061000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.DEPOSIT,
            event_subtype=HistoryEventSubType.DEPOSIT_ASSET,
            asset=A_ETH,
            balance=Balance(amount=FVal('0.2'), usd_value=ZERO),
            location_label=location_label,
            notes='Deposit 0.2 ETH in curve pool',
            counterparty=CPT_CURVE,
        ), HistoryBaseEntry(
            event_identifier=tx_hex,
            sequence_index=414,
            timestamp=1650276061000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.DEPOSIT,
            event_subtype=HistoryEventSubType.DEPOSIT_ASSET,
            asset=EthereumToken('0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84'),
            balance=Balance(amount=FVal('0.19993786'), usd_value=ZERO),
            location_label=location_label,
            notes='Deposit 0.19993786 stETH in curve pool 0xDC24316b9AE028F1497c275EB9192a3Ea0f67022',  # noqa: E501
            counterparty=CPT_CURVE,
        ), HistoryBaseEntry(
            event_identifier=tx_hex,
            sequence_index=415,
            timestamp=1650276061000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.INFORMATIONAL,
            event_subtype=HistoryEventSubType.APPROVE,
            asset=EthereumToken('0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84'),
            balance=Balance(amount=FVal('1.157920892373161954235709850E+59'), usd_value=ZERO),
            location_label=location_label,
            notes='Approve 1.157920892373161954235709850E+59 stETH of 0x767B35b9F06F6e28e5ed05eE7C27bDf992eba5d2 for spending by 0xDC24316b9AE028F1497c275EB9192a3Ea0f67022',  # noqa: E501
            counterparty='0xDC24316b9AE028F1497c275EB9192a3Ea0f67022',
        ), HistoryBaseEntry(
            event_identifier=tx_hex,
            sequence_index=416,
            timestamp=1650276061000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.RECEIVE,
            event_subtype=HistoryEventSubType.RECEIVE_WRAPPED,
            asset=EthereumToken('0x06325440D014e39736583c165C2963BA99fAf14E'),
            balance=Balance(amount=FVal('0.385232873991059423'), usd_value=ZERO),
            location_label=location_label,
            notes='Receive 0.385232873991059423 steCRV after depositing in curve pool 0xDC24316b9AE028F1497c275EB9192a3Ea0f67022',  # noqa: E501
            counterparty=CPT_CURVE,
        )]
    assert len(events) == 5
    assert events == expected_events
예제 #25
0
def test_get_transaction_receipt(
    ethereum_manager,
    call_order,
    ethereum_manager_connect_at_start,
    database,
):
    wait_until_all_nodes_connected(
        ethereum_manager_connect_at_start=ethereum_manager_connect_at_start,
        ethereum=ethereum_manager,
    )
    tx_hash = deserialize_evm_tx_hash(
        '0x12d474b6cbba04fd1a14e55ef45b1eb175985612244631b4b70450c888962a89'
    )  # noqa: E501
    result = ethereum_manager.get_transaction_receipt(tx_hash,
                                                      call_order=call_order)
    block_hash = '0x6f3a7838a8788c3371b88df170c3643d19bad896c915a7368681292882b6ad61'
    assert result['blockHash'] == block_hash
    assert len(result['logs']) == 2
    assert result['gasUsed'] == 144046
    assert result['blockNumber'] == 10840714
    assert result['logs'][0]['blockNumber'] == 10840714
    assert result['logs'][1]['blockNumber'] == 10840714
    assert result['status'] == 1
    assert result['transactionIndex'] == 110
    assert result['logs'][0]['transactionIndex'] == 110
    assert result['logs'][1]['transactionIndex'] == 110
    assert result['logs'][0]['logIndex'] == 235
    assert result['logs'][1]['logIndex'] == 236

    from_addy = make_ethereum_address()
    to_addy = make_ethereum_address()
    database.add_blockchain_accounts(
        blockchain=SupportedBlockchain.ETHEREUM,
        account_data=[
            BlockchainAccountData(address=from_addy),
            BlockchainAccountData(address=to_addy),
        ],
    )
    db = DBEthTx(database)
    db.add_ethereum_transactions(
        [
            EthereumTransaction(  # need to add the tx first
                tx_hash=tx_hash,
                timestamp=1,  # all other fields don't matter for this test
                block_number=1,
                from_address=from_addy,
                to_address=to_addy,
                value=1,
                gas=1,
                gas_price=1,
                gas_used=1,
                input_data=b'',
                nonce=1,
            )
        ],
        relevant_address=from_addy,
    )

    # also test receipt can be stored and retrieved from the DB.
    # This tests that all node types (say openethereum) are processed properly
    db.add_receipt_data(result)
    receipt = db.get_receipt(tx_hash)
    assert receipt == EthereumTxReceipt(
        tx_hash=tx_hash,
        contract_address=None,
        status=True,
        type=0,
        logs=[
            EthereumTxReceiptLog(
                log_index=235,
                data=
                b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02T\x0b\xe4\x00',  # noqa: E501
                address='0x5bEaBAEBB3146685Dd74176f68a0721F91297D37',
                removed=False,
                topics=[
                    b'\xdd\xf2R\xad\x1b\xe2\xc8\x9bi\xc2\xb0h\xfc7\x8d\xaa\x95+\xa7\xf1c\xc4\xa1\x16(\xf5ZM\xf5#\xb3\xef',  # noqa: E501
                    b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s(*c\xf0\xe3\xd7\xe9`EuB\x0fwsa\xec\xa3\xc8j',  # noqa: E501
                    b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb6 \xf1\x93ME\x84\xdd\xa6\x99\x9e\xdc\xad\xd3)\x81)dj\xa5',  # noqa: E501
                ]),
            EthereumTxReceiptLog(
                log_index=236,
                data=
                b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb6 \xf1\x93ME\x84\xdd\xa6\x99\x9e\xdc\xad\xd3)\x81)dj\xa5\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb6 \xf1\x93ME\x84\xdd\xa6\x99\x9e\xdc\xad\xd3)\x81)dj\xa5\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00[\xea\xba\xeb\xb3\x14f\x85\xddt\x17oh\xa0r\x1f\x91)}7\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02T\x0b\xe4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r\xe0\xb6\xb3\xa7d\x00\x00',  # noqa: E501
                address='0x73282A63F0e3D7e9604575420F777361ecA3C86A',
                removed=False,
                topics=[
                    b'\xd6\xd4\xf5h\x1c$l\x9fB\xc2\x03\xe2\x87\x97Z\xf1`\x1f\x8d\xf8\x03Z\x92Q\xf7\x9a\xab\\\x8f\t\xe2\xf8'
                ],  # noqa: E501
            ),
        ])
예제 #26
0
def test_kyber_legacy_old_contract(database, ethereum_manager,
                                   eth_transactions):
    """Data for trade taken from
    https://etherscan.io/tx/0xe9cc9f27ef2a09fe23abc886a0a0f7ae19d9e2eb73663e1e41e07a3e0c011b87
    """
    msg_aggregator = MessagesAggregator()
    tx_hex = '0xe9cc9f27ef2a09fe23abc886a0a0f7ae19d9e2eb73663e1e41e07a3e0c011b87'
    evmhash = deserialize_evm_tx_hash(tx_hex)
    transaction = EthereumTransaction(
        tx_hash=evmhash,
        timestamp=1591043988,
        block_number=10182160,
        from_address='0x6d379cb5BA04c09293b21Bf314E7aba3FfEAaF5b',
        to_address='0x818E6FECD516Ecc3849DAf6845e3EC868087B755',
        value=0,
        gas=600000,
        gas_price=22990000000,
        gas_used=527612,
        input_data=hexstring_to_bytes(
            '0xcb3c28c7000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000002aea540000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000000000000000000000006d379cb5ba04c09293b21bf314e7aba3ffeaaf5b8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e5f611df3b9ac000000000000000000000000f1aa99c69715f423086008eb9d06dc1e35cc504d'
        ),  # noqa: E501
        nonce=1,
    )
    receipt = EthereumTxReceipt(
        tx_hash=evmhash,
        contract_address=None,
        status=True,
        type=0,
        logs=[
            EthereumTxReceiptLog(
                log_index=87,
                data=hexstring_to_bytes(
                    '0x0000000000000000000000000000000000000000000000000000000002aea540'
                ),  # noqa: E501
                address=string_to_ethereum_address(
                    '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'),
                removed=False,
                topics=[
                    hexstring_to_bytes(
                        '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'
                    ),  # noqa: E501
                    hexstring_to_bytes(
                        '0x0000000000000000000000006d379cb5ba04c09293b21bf314e7aba3ffeaaf5b'
                    ),  # noqa: E501
                    hexstring_to_bytes(
                        '0x00000000000000000000000065bf64ff5f51272f729bdcd7acfb00677ced86cd'
                    ),  # noqa: E501
                ],
            ),
            EthereumTxReceiptLog(
                log_index=93,
                data=hexstring_to_bytes(
                    '0x000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000000000000000000000000000000000000000000000000000000002aea540000000000000000000000000000000000000000000000000029a80338e28df730000000000000000000000006d379cb5ba04c09293b21bf314e7aba3ffeaaf5b000000000000000000000000000000000000000000000000029a80338e28df730000000000000000000000001670dfb52806de7789d5cf7d5c005cf7083f9a5d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000000'
                ),  # noqa: E501
                address=string_to_ethereum_address(
                    '0x65bF64Ff5f51272f729BDcD7AcFB00677ced86Cd'),
                removed=False,
                topics=[
                    hexstring_to_bytes(
                        '0xd30ca399cb43507ecec6a629a35cf45eb98cda550c27696dcb0d8c4a3873ce6c'
                    ),  # noqa: E501
                    hexstring_to_bytes(
                        '0x0000000000000000000000006d379cb5ba04c09293b21bf314e7aba3ffeaaf5b'
                    ),  # noqa: E501
                ],
            ),
        ],
    )
    internal_tx = EthereumInternalTransaction(
        parent_tx_hash=evmhash,
        trace_id=27,
        timestamp=Timestamp(1591043988),
        block_number=10182160,
        from_address='0x65bF64Ff5f51272f729BDcD7AcFB00677ced86Cd',
        to_address='0x6d379cb5BA04c09293b21Bf314E7aba3FfEAaF5b',
        value=187603293406027635,
    )
    dbethtx = DBEthTx(database)
    dbethtx.add_ethereum_transactions([transaction], relevant_address=None)
    dbethtx.add_ethereum_internal_transactions(
        [internal_tx],
        relevant_address='0x6d379cb5BA04c09293b21Bf314E7aba3FfEAaF5b'
    )  # noqa: E501
    decoder = EVMTransactionDecoder(
        database=database,
        ethereum_manager=ethereum_manager,
        eth_transactions=eth_transactions,
        msg_aggregator=msg_aggregator,
    )
    events = decoder.decode_transaction(transaction=transaction,
                                        tx_receipt=receipt)

    assert len(events) == 3
    expected_events = [
        HistoryBaseEntry(
            event_identifier=
            '0xe9cc9f27ef2a09fe23abc886a0a0f7ae19d9e2eb73663e1e41e07a3e0c011b87',
            sequence_index=0,
            timestamp=1591043988000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.FEE,
            asset=A_ETH,
            balance=Balance(
                amount=FVal(0.01212979988),
                usd_value=FVal(0),
            ),
            location_label='0x6d379cb5BA04c09293b21Bf314E7aba3FfEAaF5b',
            notes=
            'Burned 0.01212979988 ETH in gas from 0x6d379cb5BA04c09293b21Bf314E7aba3FfEAaF5b',  # noqa: E501
            counterparty=CPT_GAS,
        ),
        HistoryBaseEntry(
            event_identifier=
            '0xe9cc9f27ef2a09fe23abc886a0a0f7ae19d9e2eb73663e1e41e07a3e0c011b87',
            sequence_index=1,
            timestamp=1591043988000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.TRADE,
            event_subtype=HistoryEventSubType.SPEND,
            asset=A_USDC,
            balance=Balance(amount=FVal(45), usd_value=FVal(0)),
            location_label='0x6d379cb5BA04c09293b21Bf314E7aba3FfEAaF5b',
            notes='Swap 45 USDC in kyber',
            counterparty='kyber legacy',
        ),
        HistoryBaseEntry(
            event_identifier=
            '0xe9cc9f27ef2a09fe23abc886a0a0f7ae19d9e2eb73663e1e41e07a3e0c011b87',
            sequence_index=89,
            timestamp=1591043988000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.TRADE,
            event_subtype=HistoryEventSubType.RECEIVE,
            asset=A_ETH,
            balance=Balance(
                amount=FVal('0.187603293406027635'),
                usd_value=FVal(0),
            ),
            location_label='0x6d379cb5BA04c09293b21Bf314E7aba3FfEAaF5b',
            notes='Receive 0.187603293406027635 ETH from kyber swap',
            counterparty='kyber legacy',
        )
    ]
    assert events == expected_events
예제 #27
0
def test_query_transactions_over_limit(
    rotkehlchen_api_server,
    ethereum_accounts,
    start_with_valid_premium,
):
    start_ts = 0
    end_ts = 1598453214
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen
    db = rotki.data.db
    all_transactions_num = FREE_ETH_TX_LIMIT + 50
    transactions = [
        EthereumTransaction(
            tx_hash=x.to_bytes(2, byteorder='little'),
            timestamp=x,
            block_number=x,
            from_address=ethereum_accounts[0],
            to_address=make_ethereum_address(),
            value=x,
            gas=x,
            gas_price=x,
            gas_used=x,
            input_data=x.to_bytes(2, byteorder='little'),
            nonce=x,
        ) for x in range(FREE_ETH_TX_LIMIT - 10)
    ]
    transactions.extend([
        EthereumTransaction(
            tx_hash=(x + 500).to_bytes(2, byteorder='little'),
            timestamp=x,
            block_number=x,
            from_address=ethereum_accounts[1],
            to_address=make_ethereum_address(),
            value=x,
            gas=x,
            gas_price=x,
            gas_used=x,
            input_data=x.to_bytes(2, byteorder='little'),
            nonce=x,
        ) for x in range(60)
    ])

    dbethtx = DBEthTx(db)
    dbethtx.add_ethereum_transactions(transactions)
    # Also make sure to update query ranges so as not to query etherscan at all
    for address in ethereum_accounts:
        DBQueryRanges(db).update_used_query_range(
            location_string=f'ethtxs_{address}',
            start_ts=start_ts,
            end_ts=end_ts,
            ranges_to_query=[],
        )

    free_expected_entries_total = [FREE_ETH_TX_LIMIT - 10, 10]
    free_expected_entries_found = [FREE_ETH_TX_LIMIT - 10, 60]
    premium_expected_entries = [FREE_ETH_TX_LIMIT - 10, 60]

    # Check that we get all transactions correctly even if we query two times
    for _ in range(2):
        response = requests.post(
            api_url_for(
                rotkehlchen_api_server,
                'limitscounterresetresource',
                location='ethereum_transactions',
            ), )
        assert_simple_ok_response(response)
        for idx, address in enumerate(ethereum_accounts):
            response = requests.get(
                api_url_for(
                    rotkehlchen_api_server,
                    'ethereumtransactionsresource',
                ),
                json={
                    'from_timestamp': start_ts,
                    'to_timestamp': end_ts,
                    'address': address
                },
            )
            result = assert_proper_response_with_result(response)
            if start_with_valid_premium:
                assert len(result['entries']) == premium_expected_entries[idx]
                assert result['entries_total'] == all_transactions_num
                assert result['entries_found'] == premium_expected_entries[idx]
                assert result['entries_limit'] == -1
            else:
                assert len(
                    result['entries']) == free_expected_entries_total[idx]
                assert result['entries_total'] == all_transactions_num
                assert result['entries_found'] == free_expected_entries_found[
                    idx]
                assert result['entries_limit'] == FREE_ETH_TX_LIMIT
예제 #28
0
def test_query_transactions_from_to_address(
    rotkehlchen_api_server,
    ethereum_accounts,
):
    """Make sure that if a transaction is just being sent to an address it's also returned."""
    start_ts = 0
    end_ts = 1598453214
    rotki = rotkehlchen_api_server.rest_api.rotkehlchen
    db = rotki.data.db
    transactions = [
        EthereumTransaction(
            tx_hash=b'1',
            timestamp=0,
            block_number=0,
            from_address=ethereum_accounts[0],
            to_address=make_ethereum_address(),
            value=1,
            gas=1,
            gas_price=1,
            gas_used=1,
            input_data=b'',
            nonce=0,
        ),
        EthereumTransaction(
            tx_hash=b'2',
            timestamp=0,
            block_number=0,
            from_address=ethereum_accounts[0],
            to_address=ethereum_accounts[1],
            value=1,
            gas=1,
            gas_price=1,
            gas_used=1,
            input_data=b'',
            nonce=1,
        ),
        EthereumTransaction(
            tx_hash=b'3',
            timestamp=0,
            block_number=0,
            from_address=make_ethereum_address(),
            to_address=ethereum_accounts[0],
            value=1,
            gas=1,
            gas_price=1,
            gas_used=1,
            input_data=b'',
            nonce=55,
        )
    ]
    dbethtx = DBEthTx(db)
    dbethtx.add_ethereum_transactions(transactions)
    # Also make sure to update query ranges so as not to query etherscan at all
    for address in ethereum_accounts:
        DBQueryRanges(db).update_used_query_range(
            location_string=f'ethtxs_{address}',
            start_ts=start_ts,
            end_ts=end_ts,
            ranges_to_query=[],
        )

    expected_entries = {ethereum_accounts[0]: 3, ethereum_accounts[1]: 1}
    # Check that we get all transactions correctly even if we query two times
    for _ in range(2):
        for address in ethereum_accounts:
            response = requests.get(
                api_url_for(
                    rotkehlchen_api_server,
                    'ethereumtransactionsresource',
                ),
                json={
                    'from_timestamp': start_ts,
                    'to_timestamp': end_ts,
                    'address': address
                },
            )
            result = assert_proper_response_with_result(response)
            assert len(result['entries']) == expected_entries[address]
            assert result['entries_limit'] == FREE_ETH_TX_LIMIT
            assert result['entries_found'] == expected_entries[address]
            assert result['entries_total'] == 3
예제 #29
0
def test_curve_deposit(database, ethereum_manager, eth_transactions):
    """Data for deposit taken from
    https://etherscan.io/tx/0x523b7df8e168315e97a836a3d516d639908814785d7df1ef1745de3e55501982
    tests that a deposit for the aave pool in curve works correctly
    """
    msg_aggregator = MessagesAggregator()
    tx_hex = '0x523b7df8e168315e97a836a3d516d639908814785d7df1ef1745de3e55501982'
    location_label = '0x57bF3B0f29E37619623994071C9e12091919675c'
    evmhash = deserialize_evm_tx_hash(tx_hex)
    transaction = EthereumTransaction(
        tx_hash=evmhash,
        timestamp=1650276061,
        block_number=14608535,
        from_address='0x57bF3B0f29E37619623994071C9e12091919675c',
        to_address='0xDeBF20617708857ebe4F679508E7b7863a8A8EeE',
        value=0,
        gas=171249,
        gas_price=22990000000,
        gas_used=171249,
        input_data=hexstring_to_bytes('0x2b6e993a000000000000000000000000000000000000000000005512b9a6a672640100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060c5f3590000000000000000000000000000000000000000000005255abbd43baa53603f90000000000000000000000000000000000000000000000000000000000000001'),  # noqa: E501
        nonce=599,
    )
    receipt = EthereumTxReceipt(
        tx_hash=evmhash,
        contract_address=None,
        status=True,
        type=0,
        logs=[
            EthereumTxReceiptLog(
                log_index=370,
                data=hexstring_to_bytes('0x000000000000000000000000000000000000000000005512b9a6a67264010000'),  # noqa: E501
                address=string_to_ethereum_address('0x6B175474E89094C44Da98b954EedeAC495271d0F'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x00000000000000000000000057bf3b0f29e37619623994071c9e12091919675c'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000debf20617708857ebe4f679508e7b7863a8a8eee'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=383,
                data=hexstring_to_bytes('0x000000000000000000000000000000000000000000000000000000060c5f3590'),  # noqa: E501
                address=string_to_ethereum_address('0xdAC17F958D2ee523a2206206994597C13D831ec7'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x00000000000000000000000057bf3b0f29e37619623994071c9e12091919675c'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000debf20617708857ebe4f679508e7b7863a8a8eee'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=396,
                data=hexstring_to_bytes('0x000000000000000000000000000000000000000000005328394d50efea7abaf4'),  # noqa: E501
                address=string_to_ethereum_address('0xFd2a8fA60Abd58Efe3EeE34dd494cD491dC14900'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x0000000000000000000000000000000000000000000000000000000000000000'),  # noqa: E501
                    hexstring_to_bytes('0x00000000000000000000000057bf3b0f29e37619623994071c9e12091919675c'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=397,
                data=hexstring_to_bytes('0x000000000000000000000000000000000000000000005512b9a6a672640100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060c5f3590000000000000000000000000000000000000000000000002038eb27e79fe96ef0000000000000000000000000000000000000000000000000000000002e973710000000000000000000000000000000000000000000000000000000001832b050000000000000000000000000000000000000000002a38dd00eecdefe02a2fcf00000000000000000000000000000000000000000026c6b056a9a8e3b89d5717'),  # noqa: E501
                address=string_to_ethereum_address('0xDeBF20617708857ebe4F679508E7b7863a8A8EeE'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0x423f6495a08fc652425cf4ed0d1f9e37e571d9b9529b1c1c23cce780b2e7df0d'),  # noqa: E501
                    hexstring_to_bytes('0x00000000000000000000000057bf3b0f29e37619623994071c9e12091919675c'),  # noqa: E501
                ],
            ),
        ],
    )

    dbethtx = DBEthTx(database)
    dbethtx.add_ethereum_transactions([transaction], relevant_address=None)
    decoder = EVMTransactionDecoder(
        database=database,
        ethereum_manager=ethereum_manager,
        eth_transactions=eth_transactions,
        msg_aggregator=msg_aggregator,
    )
    events = decoder.decode_transaction(transaction=transaction, tx_receipt=receipt)
    expected_events = [
        HistoryBaseEntry(
            event_identifier=tx_hex,
            sequence_index=0,
            timestamp=1650276061000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.FEE,
            asset=A_ETH,
            balance=Balance(
                amount=FVal(0.00393701451),
                usd_value=ZERO,
            ),
            location_label=location_label,
            notes='Burned 0.00393701451 ETH in gas from 0x57bF3B0f29E37619623994071C9e12091919675c',  # noqa: E501
            counterparty=CPT_GAS,
        ), HistoryBaseEntry(
            event_identifier=tx_hex,
            sequence_index=371,
            timestamp=1650276061000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.DEPOSIT,
            event_subtype=HistoryEventSubType.DEPOSIT_ASSET,
            asset=A_DAI,
            balance=Balance(amount=FVal('401746.57'), usd_value=ZERO),
            location_label=location_label,
            notes='Deposit 401746.57 DAI in curve pool 0xDeBF20617708857ebe4F679508E7b7863a8A8EeE',
            counterparty=CPT_CURVE,
        ), HistoryBaseEntry(
            event_identifier=tx_hex,
            sequence_index=384,
            timestamp=1650276061000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.DEPOSIT,
            event_subtype=HistoryEventSubType.DEPOSIT_ASSET,
            asset=A_USDT,
            balance=Balance(amount=FVal('25977.37'), usd_value=ZERO),
            location_label=location_label,
            notes='Deposit 25977.37 USDT in curve pool 0xDeBF20617708857ebe4F679508E7b7863a8A8EeE',
            counterparty=CPT_CURVE,
        ), HistoryBaseEntry(
            event_identifier=tx_hex,
            sequence_index=397,
            timestamp=1650276061000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.RECEIVE,
            event_subtype=HistoryEventSubType.RECEIVE_WRAPPED,
            asset=EthereumToken('0xFd2a8fA60Abd58Efe3EeE34dd494cD491dC14900'),
            balance=Balance(amount=FVal('392698.416886553664731892'), usd_value=ZERO),
            location_label=location_label,
            notes='Receive 392698.416886553664731892 a3CRV after depositing in curve pool 0xDeBF20617708857ebe4F679508E7b7863a8A8EeE',  # noqa: E501
            counterparty=CPT_CURVE,
        )]
    assert len(events) == 4
    assert events == expected_events
예제 #30
0
def test_pickle_deposit(database, ethereum_manager, eth_transactions):
    """Data for deposit taken from
    https://etherscan.io/tx/0xba9a52a144d4e79580a557160e9f8269d3e5373ce44bce00ebd609754034b7bd
    """
    msg_aggregator = MessagesAggregator()
    tx_hex = '0xba9a52a144d4e79580a557160e9f8269d3e5373ce44bce00ebd609754034b7bd'
    evmhash = deserialize_evm_tx_hash(tx_hex)
    transaction = EthereumTransaction(
        tx_hash=evmhash,
        timestamp=1646375440,
        block_number=14318825,
        from_address='0x0f1a748cDF53Bbad378CE2C4429463d01CcE0C3f',
        to_address='0xb4EBc2C371182DeEa04B2264B9ff5AC4F0159C69',
        value=0,
        gas=171249,
        gas_price=22990000000,
        gas_used=171249,
        input_data=hexstring_to_bytes('0xb6b55f250000000000000000000000000000000000000000000000312ebe013bcd5d6fed'),  # noqa: E501
        nonce=507,
    )
    receipt = EthereumTxReceipt(
        tx_hash=evmhash,
        contract_address=None,
        status=True,
        type=0,
        logs=[
            EthereumTxReceiptLog(
                log_index=259,
                data=hexstring_to_bytes('0x0000000000000000000000000000000000000000000000312ebe013bcd5d6fed'),  # noqa: E501
                address=string_to_ethereum_address('0xf4d2888d29D722226FafA5d9B24F9164c092421E'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x0000000000000000000000000f1a748cdf53bbad378ce2c4429463d01cce0c3f'),  # noqa: E501
                    hexstring_to_bytes('0x000000000000000000000000b4ebc2c371182deea04b2264b9ff5ac4f0159c69'),  # noqa: E501
                ],
            ), EthereumTxReceiptLog(
                log_index=261,
                data=hexstring_to_bytes('0x00000000000000000000000000000000000000000000001e67da0f130b2d9371'),  # noqa: E501
                address=string_to_ethereum_address('0xb4EBc2C371182DeEa04B2264B9ff5AC4F0159C69'),
                removed=False,
                topics=[
                    hexstring_to_bytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),  # noqa: E501
                    hexstring_to_bytes('0x0000000000000000000000000000000000000000000000000000000000000000'),  # noqa: E501
                    hexstring_to_bytes('0x0000000000000000000000000f1a748cdf53bbad378ce2c4429463d01cce0c3f'),  # noqa: E501
                ],
            ),
        ],
    )

    dbethtx = DBEthTx(database)
    dbethtx.add_ethereum_transactions([transaction], relevant_address=None)
    decoder = EVMTransactionDecoder(
        database=database,
        ethereum_manager=ethereum_manager,
        eth_transactions=eth_transactions,
        msg_aggregator=msg_aggregator,
    )
    events = decoder.decode_transaction(transaction=transaction, tx_receipt=receipt)
    assert len(events) == 3
    expected_events = [
        HistoryBaseEntry(
            event_identifier='0xba9a52a144d4e79580a557160e9f8269d3e5373ce44bce00ebd609754034b7bd',
            sequence_index=0,
            timestamp=1646375440000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.FEE,
            asset=A_ETH,
            balance=Balance(
                amount=FVal(0.00393701451),
                usd_value=ZERO,
            ),
            location_label='0x0f1a748cDF53Bbad378CE2C4429463d01CcE0C3f',
            notes='Burned 0.00393701451 ETH in gas from 0x0f1a748cDF53Bbad378CE2C4429463d01CcE0C3f',  # noqa: E501
            counterparty=CPT_GAS,
        ), HistoryBaseEntry(
            event_identifier='0xba9a52a144d4e79580a557160e9f8269d3e5373ce44bce00ebd609754034b7bd',
            sequence_index=260,
            timestamp=1646375440000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.DEPOSIT,
            event_subtype=HistoryEventSubType.DEPOSIT_ASSET,
            asset=EthereumToken('0xf4d2888d29D722226FafA5d9B24F9164c092421E'),
            balance=Balance(amount=FVal('907.258590539447889901'), usd_value=ZERO),
            location_label='0x0f1a748cDF53Bbad378CE2C4429463d01CcE0C3f',
            notes='Deposit 907.258590539447889901 LOOKS in pickle contract',
            counterparty='pickle finance',
        ), HistoryBaseEntry(
            event_identifier='0xba9a52a144d4e79580a557160e9f8269d3e5373ce44bce00ebd609754034b7bd',
            sequence_index=262,
            timestamp=1646375440000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.RECEIVE,
            event_subtype=HistoryEventSubType.RECEIVE_WRAPPED,
            asset=EthereumToken('0xb4EBc2C371182DeEa04B2264B9ff5AC4F0159C69'),
            balance=Balance(amount=FVal('560.885632516582380401'), usd_value=ZERO),
            location_label='0x0f1a748cDF53Bbad378CE2C4429463d01CcE0C3f',
            notes='Receive 560.885632516582380401 pLOOKS after depositing in pickle contract',
            counterparty='pickle finance',
        )]
    assert events == expected_events