Exemplo n.º 1
0
def test_compound_ether_withdraw(database, ethereum_manager,
                                 function_scope_messages_aggregator):
    """Data taken from:
    https://etherscan.io/tx/0x024bd402420c3ba2f95b875f55ce2a762338d2a14dac4887b78174254c9ab807
    """
    # TODO: For faster tests hard-code the transaction and the logs here so no remote query needed
    tx_hash = deserialize_evm_tx_hash(
        '0x024bd402420c3ba2f95b875f55ce2a762338d2a14dac4887b78174254c9ab807'
    )  # noqa: E501
    events = get_decoded_events_of_transaction(
        ethereum_manager=ethereum_manager,
        database=database,
        msg_aggregator=function_scope_messages_aggregator,
        tx_hash=tx_hash,
    )
    expected_events = [
        HistoryBaseEntry(
            event_identifier=tx_hash.hex(),  # pylint: disable=no-member
            sequence_index=0,
            timestamp=1598813490000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.FEE,
            asset=A_ETH,
            balance=Balance(amount=FVal('0.02858544'), usd_value=ZERO),
            location_label=ADDY,
            notes=f'Burned 0.02858544 ETH in gas from {ADDY}',
            counterparty=CPT_GAS,
        ),
        HistoryBaseEntry(
            event_identifier=tx_hash.hex(),  # pylint: disable=no-member
            sequence_index=1,
            timestamp=1598813490000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.RETURN_WRAPPED,
            asset=A_CETH,
            balance=Balance(amount=FVal('24.97649991'), usd_value=ZERO),
            location_label=ADDY,
            notes='Return 24.97649991 cETH to compound',
            counterparty=CPT_COMPOUND,
        ),
        HistoryBaseEntry(
            event_identifier=tx_hash.hex(),  # pylint: disable=no-member
            sequence_index=2,
            timestamp=1598813490000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.WITHDRAWAL,
            event_subtype=HistoryEventSubType.REMOVE_ASSET,
            asset=A_ETH,
            balance=Balance(amount=FVal('0.500003923413507454'),
                            usd_value=ZERO),
            location_label=ADDY,
            notes='Withdraw 0.500003923413507454 ETH from compound',
            counterparty=CPT_COMPOUND,
        )
    ]
    assert events == expected_events
Exemplo n.º 2
0
def test_compound_ether_deposit(database, ethereum_manager,
                                function_scope_messages_aggregator):
    """Data taken from:
    https://etherscan.io/tx/0x06a8b9f758b0471886186c2a48dea189b3044916c7f94ee7f559026fefd91c39
    """
    # TODO: For faster tests hard-code the transaction and the logs here so no remote query needed
    tx_hash = deserialize_evm_tx_hash(
        '0x06a8b9f758b0471886186c2a48dea189b3044916c7f94ee7f559026fefd91c39'
    )  # noqa: E501
    events = get_decoded_events_of_transaction(
        ethereum_manager=ethereum_manager,
        database=database,
        msg_aggregator=function_scope_messages_aggregator,
        tx_hash=tx_hash,
    )
    expected_events = [
        HistoryBaseEntry(
            event_identifier=tx_hash.hex(),  # pylint: disable=no-member
            sequence_index=0,
            timestamp=1598639099000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.FEE,
            asset=A_ETH,
            balance=Balance(amount=FVal('0.014122318'), usd_value=ZERO),
            location_label=ADDY,
            notes=f'Burned 0.014122318 ETH in gas from {ADDY}',
            counterparty=CPT_GAS,
        ),
        HistoryBaseEntry(
            event_identifier=tx_hash.hex(),  # pylint: disable=no-member
            sequence_index=1,
            timestamp=1598639099000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.DEPOSIT,
            event_subtype=HistoryEventSubType.DEPOSIT_ASSET,
            asset=A_ETH,
            balance=Balance(amount=FVal('0.5'), usd_value=ZERO),
            location_label=ADDY,
            notes='Deposit 0.5 ETH to compound',
            counterparty=CPT_COMPOUND,
        ),
        HistoryBaseEntry(
            event_identifier=tx_hash.hex(),  # pylint: disable=no-member
            sequence_index=33,
            timestamp=1598639099000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.RECEIVE,
            event_subtype=HistoryEventSubType.RECEIVE_WRAPPED,
            asset=A_CETH,
            balance=Balance(amount=FVal('24.97649991'), usd_value=ZERO),
            location_label=ADDY,
            notes='Receive 24.97649991 cETH from compound',
            counterparty=CPT_COMPOUND,
        )
    ]
    assert events == expected_events
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)
Exemplo n.º 4
0
def test_kraken_staking_events(accountant, google_service):
    """
    Test that staking events from kraken are correctly processed
    """
    history = [
        HistoryBaseEntry(
            event_identifier='XXX',
            sequence_index=0,
            timestamp=1640493374000,
            location=Location.KRAKEN,
            location_label='Kraken 1',
            asset=A_ETH2,
            balance=Balance(
                amount=FVal(0.0000541090),
                usd_value=FVal(0.212353475950),
            ),
            notes=None,
            event_type=HistoryEventType.STAKING,
            event_subtype=HistoryEventSubType.REWARD,
        ),
        HistoryBaseEntry(
            event_identifier='YYY',
            sequence_index=0,
            timestamp=1636638550000,
            location=Location.KRAKEN,
            location_label='Kraken 1',
            asset=A_ETH2,
            balance=Balance(
                amount=FVal(0.0000541090),
                usd_value=FVal(0.212353475950),
            ),
            notes=None,
            event_type=HistoryEventType.STAKING,
            event_subtype=HistoryEventSubType.REWARD,
        )
    ]
    _, events = accounting_history_process(
        accountant,
        start_ts=1636638549,
        end_ts=1640493376,
        history_list=history,
    )
    no_message_errors(accountant.msg_aggregator)
    expected_pnls = PnlTotals({
        AccountingEventType.STAKING:
        PNL(taxable=FVal('0.471505826'), free=ZERO),
    })
    check_pnls_and_csv(accountant, expected_pnls, google_service)
    assert len(events) == 2
    expected_pnls = [FVal('0.25114638241'), FVal('0.22035944359')]
    for idx, event in enumerate(events):
        assert event.pnl.taxable == expected_pnls[idx]
        assert event.type == AccountingEventType.STAKING
Exemplo n.º 5
0
def test_gitcoin_old_donation(database, ethereum_manager, function_scope_messages_aggregator):
    """Data taken from
    https://etherscan.io/tx/0x811ba23a10c76111289133ec6f90d3c33a604baa50053739210e870687a456d9
    """
    # TODO: For faster tests hard-code the transaction and the logs here so no remote query needed
    tx_hash = deserialize_evm_tx_hash('0x811ba23a10c76111289133ec6f90d3c33a604baa50053739210e870687a456d9')  # noqa: E501
    events = get_decoded_events_of_transaction(
        ethereum_manager=ethereum_manager,
        database=database,
        msg_aggregator=function_scope_messages_aggregator,
        tx_hash=tx_hash,
    )
    expected_events = [
        HistoryBaseEntry(
            event_identifier=tx_hash.hex(),  # pylint: disable=no-member
            sequence_index=0,
            timestamp=1569924574000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.FEE,
            asset=A_ETH,
            balance=Balance(amount=FVal('0.000055118'), usd_value=ZERO),
            location_label=ADDY,
            notes=f'Burned 0.000055118 ETH in gas from {ADDY}',
            counterparty=CPT_GAS,
        ), HistoryBaseEntry(
            event_identifier=tx_hash.hex(),  # pylint: disable=no-member
            sequence_index=164,
            timestamp=1569924574000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.DONATE,
            asset=A_SAI,
            balance=Balance(amount=FVal('0.95'), usd_value=ZERO),
            location_label=ADDY,
            notes='Donate 0.95 SAI to 0xEbDb626C95a25f4e304336b1adcAd0521a1Bdca1 via gitcoin',  # noqa: E501
            counterparty=CPT_GITCOIN,
        ), HistoryBaseEntry(
            event_identifier=tx_hash.hex(),  # pylint: disable=no-member
            sequence_index=165,
            timestamp=1569924574000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.DONATE,
            asset=A_SAI,
            balance=Balance(amount=FVal('0.05'), usd_value=ZERO),
            location_label=ADDY,
            notes='Donate 0.05 SAI to 0x00De4B13153673BCAE2616b67bf822500d325Fc3 via gitcoin',  # noqa: E501
            counterparty=CPT_GITCOIN,
        ),
    ]
    assert events == expected_events
Exemplo n.º 6
0
    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,
        )
Exemplo n.º 7
0
    def decode_proxy_creation(
        self,
        tx_log: EthereumTxReceiptLog,
        transaction: EthereumTransaction,
        decoded_events: List[HistoryBaseEntry],  # pylint: disable=unused-argument
        all_logs: List[EthereumTxReceiptLog],  # pylint: disable=unused-argument
        action_items: List[ActionItem],  # pylint: disable=unused-argument
    ) -> Tuple[Optional[HistoryBaseEntry], Optional[ActionItem]]:
        if tx_log.topics[
                0] == b'%\x9b0\xca9\x88\\m\x80\x1a\x0b]\xbc\x98\x86@\xf3\xc2^/7S\x1f\xe18\xc5\xc5\xaf\x89U\xd4\x1b':  # noqa: E501
            owner_address = hex_or_bytes_to_address(tx_log.topics[2])
            if not self.base.is_tracked(owner_address):
                return None, None

            proxy_address = hex_or_bytes_to_address(tx_log.data[0:32])
            notes = f'Create DSR proxy {proxy_address} with owner {owner_address}'
            event = 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,
                # 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.DEPLOY,
                counterparty=proxy_address,
            )
            return event, None

        return None, None
Exemplo n.º 8
0
    def edit_history_event(self, event: HistoryBaseEntry) -> Tuple[bool, str]:
        """Edit a history entry to the DB. Returns the edited entry"""
        cursor = self.db.conn.cursor()
        try:
            cursor.execute(
                'UPDATE history_events SET event_identifier=?, sequence_index=?, timestamp=?, '
                'location=?, location_label=?, asset=?, amount=?, usd_value=?, notes=?, '
                'type=?, subtype=?, counterparty=?, extra_data=? WHERE identifier=?',
                (*event.serialize_for_db(), event.identifier),
            )
        except sqlcipher.IntegrityError:  # pylint: disable=no-member
            msg = (
                f'Tried to edit event to have event_identifier {event.event_identifier} and '
                f'sequence_index {event.sequence_index} but it already exists'
            )
            return False, msg

        if cursor.rowcount != 1:
            msg = f'Tried to edit event with id {event.identifier} but could not find it in the DB'
            return False, msg
        cursor.execute(
            'INSERT OR IGNORE INTO history_events_mappings(parent_identifier, value) '
            'VALUES(?, ?)',
            (event.identifier, HISTORY_MAPPING_CUSTOMIZED),
        )

        self.db.update_last_write()
        return True, ''
Exemplo n.º 9
0
    def add_history_event(
            self,
            event: HistoryBaseEntry,
            mapping_value: Optional[str] = None,
    ) -> int:
        """Insert a single history entry to the DB. Returns its identifier.

        Optionally map it to a specific value used to map attributes
        to some events

        May raise:
        - DeserializationError if the event could not be serialized for the DB
        - sqlcipher.DatabaseError: If anything went wrong at insertion
        """
        cursor = self.db.conn.cursor()
        cursor.execute(HISTORY_INSERT, event.serialize_for_db())
        identifier = cursor.lastrowid

        if mapping_value is not None:
            cursor.execute(
                'INSERT OR IGNORE INTO history_events_mappings(parent_identifier, value) '
                'VALUES(?, ?)',
                (identifier, mapping_value),
            )

        self.db.update_last_write()
        return identifier
Exemplo n.º 10
0
    def get_history_events(
        self,
        filter_query: HistoryEventFilterQuery,
        has_premium: bool,
    ) -> List[HistoryBaseEntry]:
        """
        Get history events using the provided query filter
        """
        query, bindings = filter_query.prepare()
        cursor = self.db.conn.cursor()

        if has_premium:
            query = 'SELECT * from history_events ' + query
            results = cursor.execute(query, bindings)
        else:
            query = 'SELECT * FROM (SELECT * from history_events ORDER BY timestamp DESC, sequence_index ASC LIMIT ?) ' + query  # noqa: E501
            results = cursor.execute(query, [FREE_HISTORY_EVENTS_LIMIT] + bindings)

        output = []
        for entry in results:
            try:
                output.append(HistoryBaseEntry.deserialize_from_db(entry))
            except (DeserializationError, UnknownAsset) as e:
                log.debug(f'Failed to deserialize history event {entry} due to {str(e)}')

        return output
Exemplo n.º 11
0
    def _decode_vault_creation(
        self,
        tx_log: EthereumTxReceiptLog,
        transaction: EthereumTransaction,
        decoded_events: List[HistoryBaseEntry],  # pylint: disable=unused-argument
        all_logs: List[EthereumTxReceiptLog],  # pylint: disable=unused-argument
    ) -> Tuple[Optional[HistoryBaseEntry], Optional[ActionItem]]:
        owner_address = self._get_address_or_proxy(
            hex_or_bytes_to_address(tx_log.topics[2]))
        if owner_address is None:
            return None, None

        if not self.base.is_tracked(owner_address):
            return None, None

        cdp_id = hex_or_bytes_to_int(tx_log.topics[3])
        notes = f'Create MakerDAO vault with id {cdp_id} and owner {owner_address}'
        event = 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,
            # 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.DEPLOY,
            counterparty='makerdao vault',
        )
        return event, None
Exemplo n.º 12
0
def test_receiving_value_from_tx(accountant, google_service):
    """
    Test that receiving a transaction that provides value works fine
    """
    addr2 = make_ethereum_address()
    tx_hash = '0x5cc0e6e62753551313412492296d5e57bea0a9d1ce507cc96aa4aa076c5bde7a'
    history = [
        HistoryBaseEntry(
            event_identifier=tx_hash,
            sequence_index=0,
            timestamp=1569924574000,
            location=Location.BLOCKCHAIN,
            location_label=make_ethereum_address(),
            asset=A_ETH,
            balance=Balance(amount=FVal('1.5')),
            notes=f'Received 1.5 ETH from {addr2}',
            event_type=HistoryEventType.RECEIVE,
            event_subtype=HistoryEventSubType.NONE,
            counterparty=addr2,
        )
    ]
    accounting_history_process(
        accountant,
        start_ts=0,
        end_ts=1640493376,
        history_list=history,
    )
    no_message_errors(accountant.msg_aggregator)
    expected_pnls = PnlTotals({
        AccountingEventType.TRANSACTION_EVENT:
        PNL(taxable=FVal('242.385'), free=ZERO),
    })
    check_pnls_and_csv(accountant, expected_pnls, google_service)
Exemplo n.º 13
0
def test_hop_l2_deposit(database, ethereum_manager,
                        function_scope_messages_aggregator):
    """Data taken from
    https://etherscan.io/tx/0xd46640417a686b399b2f2a920b0c58a35095759365cbe7b795bddec34b8c5eee
    """
    # TODO: For faster tests hard-code the transaction and the logs here so no remote query needed
    tx_hash = deserialize_evm_tx_hash(
        '0xd46640417a686b399b2f2a920b0c58a35095759365cbe7b795bddec34b8c5eee'
    )  # noqa: E501
    events = get_decoded_events_of_transaction(
        ethereum_manager=ethereum_manager,
        database=database,
        msg_aggregator=function_scope_messages_aggregator,
        tx_hash=tx_hash,
    )
    expected_events = [
        HistoryBaseEntry(
            event_identifier=tx_hash.hex(),  # pylint: disable=no-member
            sequence_index=0,
            timestamp=1653219722000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.FEE,
            asset=A_ETH,
            balance=Balance(amount=FVal('0.001964214783875487')),
            location_label=ADDY,
            notes=f'Burned 0.001964214783875487 ETH in gas from {ADDY}',
            counterparty=CPT_GAS,
        ),
        HistoryBaseEntry(
            event_identifier=tx_hash.hex(),  # pylint: disable=no-member
            sequence_index=1,
            timestamp=1653219722000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.TRANSFER,
            event_subtype=HistoryEventSubType.BRIDGE,
            asset=A_ETH,
            balance=Balance(amount=FVal('0.2')),
            location_label=ADDY,
            notes=
            'Bridge 0.2 ETH to Optimism at the same address via Hop protocol',
            counterparty=CPT_HOP,
        )
    ]
    assert expected_events == events
Exemplo n.º 14
0
    def _decode_order_placement(  # pylint: disable=no-self-use
        self,
        tx_log: EthereumTxReceiptLog,
        transaction: EthereumTransaction,  # pylint: disable=unused-argument
        decoded_events: List[HistoryBaseEntry],  # pylint: disable=unused-argument
        all_logs: List[EthereumTxReceiptLog],  # pylint: disable=unused-argument
        action_items: List[ActionItem],  # pylint: disable=unused-argument
    ) -> Tuple[Optional[HistoryBaseEntry], Optional[ActionItem]]:
        """Some docs: https://docs.gnosis.io/protocol/docs/tutorial-limit-orders/"""
        topic_data, log_data = self.contract.decode_event(
            tx_log=tx_log,
            event_name='OrderPlacement',
            argument_names=('owner', 'index', 'buyToken', 'sellToken',
                            'validFrom', 'validUntil', 'priceNumerator',
                            'priceDenominator'),  # noqa: E501
        )
        owner = topic_data[0]
        if not self.base.is_tracked(owner):
            return None, None

        result = multicall_specific(
            ethereum=self.ethereum,
            contract=self.contract,
            method_name='tokenIdToAddressMap',
            arguments=[[topic_data[1]], [topic_data[2]]],
        )  # The resulting addresses are non checksumed but they can be found in the DB
        buy_token = ethaddress_to_asset(result[0][0])
        if buy_token is None:
            return None, None
        sell_token = ethaddress_to_asset(result[1][0])
        if sell_token is None:
            return None, None

        buy_amount = asset_normalized_value(amount=log_data[3],
                                            asset=buy_token)
        sell_amount = asset_normalized_value(amount=log_data[4],
                                             asset=sell_token)
        event = 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,
            # Asset means nothing here since the event is informational. TODO: Improve?
            asset=sell_token,
            balance=Balance(amount=sell_amount),
            notes=
            f'Place an order in DXDao Mesa to sell {sell_amount} {sell_token.symbol} for {buy_amount} {buy_token.symbol}',  # noqa: E501
            event_type=HistoryEventType.INFORMATIONAL,
            event_subtype=HistoryEventSubType.PLACE_ORDER,
            counterparty=CPT_DXDAO_MESA,
        )
        return event, None
Exemplo n.º 15
0
def test_claim_aidrop(database, ethereum_manager, function_scope_messages_aggregator):
    """Data taken from
    https://etherscan.io/tx/0x1e58aed1baf70b57e6e3e880e1890e7fe607fddc94d62986c38fe70e483e594b
    """
    # TODO: For faster tests hard-code the transaction and the logs here so no remote query needed
    tx_hash = deserialize_evm_tx_hash('0x1e58aed1baf70b57e6e3e880e1890e7fe607fddc94d62986c38fe70e483e594b')  # noqa: E501
    events = get_decoded_events_of_transaction(
        ethereum_manager=ethereum_manager,
        database=database,
        msg_aggregator=function_scope_messages_aggregator,
        tx_hash=tx_hash,
    )
    expected_events = [
        HistoryBaseEntry(
            event_identifier=tx_hash.hex(),  # pylint: disable=no-member
            sequence_index=0,
            timestamp=1652910214000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.FEE,
            asset=A_ETH,
            balance=Balance(amount=FVal('0.0061843862')),
            location_label=ADDY,
            notes=f'Burned 0.0061843862 ETH in gas from {ADDY}',
            counterparty=CPT_GAS,
        ), HistoryBaseEntry(
            event_identifier=tx_hash.hex(),  # pylint: disable=no-member
            sequence_index=549,
            timestamp=1652910214000,
            location=Location.BLOCKCHAIN,
            event_type=HistoryEventType.RECEIVE,
            event_subtype=HistoryEventSubType.AIRDROP,
            asset=A_ELFI,
            balance=Balance(amount=FVal('613.8986657935664')),
            location_label=ADDY,
            notes='Claim 613.8986657935664 ELFI from element-finance airdrop and delegate it to 0x7BAFC0D5c5892f2041FD9F2415A7611042218e22',  # noqa: E501
            counterparty=CPT_ELEMENT_FINANCE,
        ),
    ]
    assert events == expected_events
Exemplo n.º 16
0
 def _maybe_enrich_curve_transfers(  # pylint: disable=no-self-use
         self,
         token: EthereumToken,  # pylint: disable=unused-argument
         tx_log: EthereumTxReceiptLog,
         transaction: EthereumTransaction,
         event: HistoryBaseEntry,
         action_items: List[ActionItem],  # pylint: disable=unused-argument
 ) -> bool:
     source_address = hex_or_bytes_to_address(tx_log.topics[1])
     to_address = hex_or_bytes_to_address(tx_log.topics[2])
     if (  # deposit give asset
         event.event_type == HistoryEventType.RECEIVE and
         event.event_subtype == HistoryEventSubType.NONE and
         source_address == CURVE_Y_DEPOSIT and
         transaction.from_address == to_address
     ):
         event.event_type = HistoryEventType.WITHDRAWAL
         event.event_subtype = HistoryEventSubType.REMOVE_ASSET
         event.counterparty = CPT_CURVE
         event.notes = f'Receive {event.balance.amount} {event.asset.symbol} from the curve pool {CURVE_Y_DEPOSIT}'  # noqa: E501
         return True
     return False
Exemplo n.º 17
0
    def _maybe_enrich_gitcoin_transfers(  # pylint: disable=no-self-use
            self,
            token: EthereumToken,  # pylint: disable=unused-argument
            tx_log: EthereumTxReceiptLog,  # pylint: disable=unused-argument
            transaction: EthereumTransaction,
            event: HistoryBaseEntry,
            action_items: List[ActionItem],  # pylint: disable=unused-argument
    ) -> bool:
        if transaction.to_address not in (
                '0xdf869FAD6dB91f437B59F1EdEFab319493D4C4cE',
                '0x7d655c57f71464B6f83811C55D84009Cd9f5221C',
        ):
            return False

        if event.event_type == HistoryEventType.SPEND:
            to_address = event.counterparty
            event.notes = f'Donate {event.balance.amount} {event.asset.symbol} to {to_address} via gitcoin'  # noqa: E501
        else:  # can only be RECEIVE
            from_address = event.counterparty
            event.notes = f'Receive donation of {event.balance.amount} {event.asset.symbol} from {from_address} via gitcoin'  # noqa: E501

        event.event_subtype = HistoryEventSubType.DONATE
        event.counterparty = CPT_GITCOIN
        return True
Exemplo n.º 18
0
    def _decode_elfi_claim(  # pylint: disable=no-self-use
        self,
        tx_log: EthereumTxReceiptLog,
        transaction: EthereumTransaction,  # pylint: disable=unused-argument
        decoded_events: List[HistoryBaseEntry],  # pylint: disable=unused-argument
        all_logs: List[EthereumTxReceiptLog],  # pylint: disable=unused-argument
        action_items: List[ActionItem],  # pylint: disable=unused-argument
    ) -> Tuple[Optional[HistoryBaseEntry], Optional[ActionItem]]:
        """Example:
        https://etherscan.io/tx/0x1e58aed1baf70b57e6e3e880e1890e7fe607fddc94d62986c38fe70e483e594b
        """
        if tx_log.topics[0] != ELFI_VOTE_CHANGE:
            return None, None

        user_address = hex_or_bytes_to_address(tx_log.topics[1])
        delegate_address = hex_or_bytes_to_address(tx_log.topics[2])
        raw_amount = hex_or_bytes_to_int(tx_log.data[0:32])
        amount = asset_normalized_value(amount=raw_amount, asset=A_ELFI)

        # now we need to find the transfer, but can't use decoded events
        # since the transfer is from one of at least 2 airdrop contracts to
        # vote/locking contract. Since neither the from, nor the to is a
        # tracked address there won't be a decoded transfer. So we search for
        # the raw log
        for other_log in all_logs:
            if other_log.topics[0] != ERC20_OR_ERC721_TRANSFER:
                continue

            transfer_raw = hex_or_bytes_to_int(other_log.data[0:32])
            if other_log.address == A_ELFI.ethereum_address and transfer_raw == raw_amount:
                delegate_str = 'self-delegate' if user_address == delegate_address else f'delegate it to {delegate_address}'  # noqa: E501
                event = 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=user_address,
                    asset=A_ELFI,
                    balance=Balance(amount=amount),
                    notes=
                    f'Claim {amount} ELFI from element-finance airdrop and {delegate_str}',
                    event_type=HistoryEventType.RECEIVE,
                    event_subtype=HistoryEventSubType.AIRDROP,
                    counterparty=CPT_ELEMENT_FINANCE,
                )
                return event, None

        return None, None
Exemplo n.º 19
0
    def _decode_swapped(  # pylint: disable=no-self-use
        self,
        tx_log: EthereumTxReceiptLog,
        transaction: EthereumTransaction,
        decoded_events: List[HistoryBaseEntry],  # pylint: disable=unused-argument
        all_logs: List[EthereumTxReceiptLog],  # pylint: disable=unused-argument
    ) -> Tuple[Optional[HistoryBaseEntry], Optional[ActionItem]]:
        """We use the Swapped event to get the fee kept by 1inch"""
        to_token_address = hex_or_bytes_to_address(tx_log.topics[2])
        to_asset = ethaddress_to_asset(to_token_address)
        if to_asset is None:
            return None, None

        to_raw = hex_or_bytes_to_int(tx_log.data[32:64])
        fee_raw = hex_or_bytes_to_int(tx_log.data[96:128])
        if fee_raw == 0:
            return None, None  # no need to do anything for zero fee taken

        full_amount = asset_normalized_value(to_raw + fee_raw, to_asset)
        sender_address = None
        for event in decoded_events:
            # Edit the full amount in the swap's receive event
            if event.event_type == HistoryEventType.TRADE and event.event_subtype == HistoryEventSubType.RECEIVE and event.counterparty == CPT_ONEINCH_V1:  # noqa: E501
                event.balance.amount = full_amount
                event.notes = f'Receive {full_amount} {event.asset.symbol} from {CPT_ONEINCH_V1} swap in {event.location_label}'  # noqa: E501
                sender_address = event.location_label
                break

        if sender_address is None:
            return None, None

        # And now create a new event for the fee
        fee_amount = asset_normalized_value(fee_raw, to_asset)
        fee_event = 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=sender_address,
            asset=to_asset,
            balance=Balance(amount=fee_amount),
            notes=
            f'Deduct {fee_amount} {to_asset.symbol} from {sender_address} as {CPT_ONEINCH_V1} fees',  # noqa: E501
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.FEE,
            counterparty=CPT_ONEINCH_V1,
        )
        return fee_event, None
Exemplo n.º 20
0
def test_gas_fees_after_year(accountant, google_service):
    """
    Test that for an expense like gas fees after year the "selling" part is tax free
    PnL, and the expense part is taxable pnl.
    """
    tx_hash = '0x5cc0e6e62753551313412492296d5e57bea0a9d1ce507cc96aa4aa076c5bde7a'
    history = [
        LedgerAction(
            identifier=0,
            timestamp=Timestamp(1539713238),  # 178.615 EUR/ETH
            action_type=LedgerActionType.
            GIFT,  # gift so not counting as income
            location=Location.KRAKEN,
            amount=FVal(1),
            asset=A_ETH,
            rate=None,
            rate_asset=None,
            link=None,
            notes='',
        ),
        HistoryBaseEntry(
            event_identifier=tx_hash,
            sequence_index=0,
            timestamp=1640493374000,  # 4072.51 EUR/ETH
            location=Location.BLOCKCHAIN,
            location_label=make_ethereum_address(),
            asset=A_ETH,
            balance=Balance(amount=FVal('0.01')),
            notes='Burned 0.01 ETH in gas',
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.FEE,
            counterparty=CPT_GAS,
        )
    ]
    accounting_history_process(
        accountant,
        start_ts=0,
        end_ts=1640493376,
        history_list=history,
    )
    no_message_errors(accountant.msg_aggregator)
    expected_pnls = PnlTotals({
        AccountingEventType.TRANSACTION_EVENT:
        PNL(taxable=FVal('-40.7251'), free=FVal('38.93895')),
    })
    check_pnls_and_csv(accountant, expected_pnls, google_service)
Exemplo n.º 21
0
    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,
                ))
Exemplo n.º 22
0
def test_include_gas_costs(accountant, google_service):
    addr1 = '0x2B888954421b424C5D3D9Ce9bB67c9bD47537d12'
    tx_hash = '0x5cc0e6e62753551313412492296d5e57bea0a9d1ce507cc96aa4aa076c5bde7a'
    history = [
        Trade(
            timestamp=1539388574,
            location=Location.EXTERNAL,
            base_asset=A_ETH,
            quote_asset=A_EUR,
            trade_type=TradeType.BUY,
            amount=FVal(10),
            rate=FVal('168.7'),
            fee=None,
            fee_currency=None,
            link=None,
        ),
        HistoryBaseEntry(
            event_identifier=tx_hash,
            sequence_index=0,
            timestamp=1569924574000,
            location=Location.BLOCKCHAIN,
            location_label=addr1,
            asset=A_ETH,
            balance=Balance(amount=FVal('0.000030921')),
            notes=f'Burned 0.000030921 ETH in gas from {addr1}',
            event_type=HistoryEventType.SPEND,
            event_subtype=HistoryEventSubType.FEE,
            counterparty=CPT_GAS,
        )
    ]
    accounting_history_process(accountant,
                               start_ts=1436979735,
                               end_ts=1619693374,
                               history_list=history)  # noqa: E501
    no_message_errors(accountant.msg_aggregator)
    expected = ZERO
    expected_pnls = PnlTotals()
    if accountant.pots[0].settings.include_gas_costs:
        expected = FVal('-0.0052163727')
        expected_pnls[AccountingEventType.TRANSACTION_EVENT] = PNL(
            taxable=expected, free=ZERO)
    check_pnls_and_csv(accountant, expected_pnls, google_service)
Exemplo n.º 23
0
def make_ethereum_event(
    index: int,
    tx_hash: Optional[bytes] = None,
    asset: Asset = A_USD,
    counterparty: Optional[str] = None,
) -> HistoryBaseEntry:
    if tx_hash is None:
        tx_hash = make_random_bytes(42)
    return HistoryBaseEntry(
        event_identifier=make_evm_tx_hash(tx_hash).hex(),  # pylint: disable=no-member
        sequence_index=index,
        identifier=index,
        timestamp=TimestampMS(0),
        location=Location.KRAKEN,
        event_type=HistoryEventType.UNKNOWN,
        event_subtype=HistoryEventSubType.NONE,
        asset=asset,
        balance=Balance(amount=ONE, usd_value=ONE),
        counterparty=counterparty,
    )
Exemplo n.º 24
0
    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
Exemplo n.º 25
0
 def _process_dsr_withdraw(
         self,
         pot: 'AccountingPot',  # pylint: disable=unused-argument
         event: HistoryBaseEntry,
         other_events: List[HistoryBaseEntry],  # pylint: disable=unused-argument
 ) -> None:
     address = cast(ChecksumEthAddress,
                    event.location_label)  # should always exist
     self.dsr_balances[address] -= event.balance.amount
     if self.dsr_balances[address] < ZERO:
         profit = -1 * self.dsr_balances[address]
         pot.add_acquisition(
             event_type=AccountingEventType.TRANSACTION_EVENT,
             notes=f'Gained {profit} DAI from Makerdao DSR',
             location=event.location,
             timestamp=event.get_timestamp_in_sec(),
             asset=A_DAI,
             amount=profit,
             taxable=True,
             extra_data={'tx_hash': event.event_identifier},
         )
         self.dsr_balances[address] = ZERO
Exemplo n.º 26
0
 def _process_vault_dai_payback(
         self,
         pot: 'AccountingPot',  # pylint: disable=unused-argument
         event: HistoryBaseEntry,
         other_events: List[HistoryBaseEntry],  # pylint: disable=unused-argument
 ) -> None:
     cdp_id = event.extra_data[
         'cdp_id']  # type: ignore  # this event should have extra_data
     self.vault_balances[cdp_id] -= event.balance.amount
     if self.vault_balances[cdp_id] < ZERO:
         loss = -1 * self.vault_balances[cdp_id]
         pot.add_spend(
             event_type=AccountingEventType.TRANSACTION_EVENT,
             notes=f'Lost {loss} DAI as debt during payback to CDP {cdp_id}',
             location=event.location,
             timestamp=event.get_timestamp_in_sec(),
             asset=A_DAI,
             amount=loss,
             taxable=True,
             extra_data={'tx_hash': event.event_identifier},
         )
         self.vault_balances[cdp_id] = ZERO
Exemplo n.º 27
0
    def _decode_withdraw_request(  # pylint: disable=no-self-use
        self,
        tx_log: EthereumTxReceiptLog,
        transaction: EthereumTransaction,  # pylint: disable=unused-argument
        decoded_events: List[HistoryBaseEntry],  # pylint: disable=unused-argument
        all_logs: List[EthereumTxReceiptLog],  # pylint: disable=unused-argument
        action_items: List[ActionItem],  # pylint: disable=unused-argument
    ) -> Tuple[Optional[HistoryBaseEntry], Optional[ActionItem]]:
        topic_data, log_data = self.contract.decode_event(
            tx_log=tx_log,
            event_name='WithdrawRequest',
            argument_names=('user', 'token', 'amount', 'batchId'),
        )
        user = topic_data[0]
        if not self.base.is_tracked(user):
            return None, None

        token = ethaddress_to_asset(topic_data[1])
        if token is None:
            return None, None
        amount = asset_normalized_value(amount=log_data[0], asset=token)

        event = 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=user,
            # Asset means nothing here since the event is informational. TODO: Improve?
            asset=token,
            balance=Balance(amount=amount),
            notes=
            f'Request a withdrawal of {amount} {token.symbol} from DXDao Mesa',
            event_type=HistoryEventType.INFORMATIONAL,
            event_subtype=HistoryEventSubType.REMOVE_ASSET,
            counterparty=CPT_DXDAO_MESA,
        )
        return event, None
Exemplo n.º 28
0
def _swap_event_indices(event1: HistoryBaseEntry, event2: HistoryBaseEntry) -> None:
    old_event1_index = event1.sequence_index
    event1.sequence_index = event2.sequence_index
    event2.sequence_index = old_event1_index
Exemplo n.º 29
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
Exemplo n.º 30
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