Пример #1
0
    def _get_vault_withdraw_events(
        self,
        vault: YearnVault,
        address: ChecksumEthAddress,
        from_block: int,
        to_block: int,
    ) -> List[YearnVaultEvent]:
        """Get all withdraw events of the underlying token to the vault"""
        events: List[YearnVaultEvent] = []
        argument_filters = {'from': vault.contract.address, 'to': address}
        withdraw_events = self.ethereum.get_logs(
            contract_address=vault.underlying_token.ethereum_address,
            abi=ERC20TOKEN_ABI,
            event_name='Transfer',
            argument_filters=argument_filters,
            from_block=from_block,
            to_block=to_block,
        )
        for withdraw_event in withdraw_events:
            timestamp = self.ethereum.get_event_timestamp(withdraw_event)
            withdraw_amount = token_normalized_value(
                token_amount=hex_or_bytes_to_int(withdraw_event['data']),
                token=vault.token,
            )
            tx_hash = withdraw_event['transactionHash']
            tx_receipt = self.ethereum.get_transaction_receipt(tx_hash)
            withdraw_index = deserialize_int_from_hex_or_int(
                withdraw_event['logIndex'],
                'yearn withdraw log index',
            )
            burn_amount = None
            for log in tx_receipt['logs']:
                found_event = (
                    log['topics'][0] ==
                    '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'
                    and  # noqa: E501
                    log['topics'][1] == address_to_bytes32(address) and
                    log['topics'][2] == address_to_bytes32(ZERO_ADDRESS))
                if found_event:
                    # found the burn log
                    burn_amount = token_normalized_value(
                        token_amount=hex_or_bytes_to_int(log['data']),
                        token=vault.token,
                    )

            if burn_amount is None:
                self.msg_aggregator.add_error(
                    f'Ignoring yearn withdraw event with tx_hash {tx_hash} and log index '
                    f'{withdraw_index} due to inability to find corresponding burn event',
                )
                continue

            withdraw_usd_price = get_usd_price_zero_if_error(
                asset=vault.underlying_token,
                time=timestamp,
                location='yearn vault withdraw',
                msg_aggregator=self.msg_aggregator,
            )
            burn_usd_price = get_usd_price_zero_if_error(
                asset=vault.token,
                time=timestamp,
                location='yearn vault withdraw',
                msg_aggregator=self.msg_aggregator,
            )
            events.append(
                YearnVaultEvent(
                    event_type='withdraw',
                    block_number=deserialize_blocknumber(
                        withdraw_event['blockNumber']),
                    timestamp=timestamp,
                    from_asset=vault.token,
                    from_value=Balance(
                        amount=burn_amount,
                        usd_value=burn_amount * burn_usd_price,
                    ),
                    to_asset=vault.underlying_token,
                    to_value=Balance(
                        amount=withdraw_amount,
                        usd_value=withdraw_amount * withdraw_usd_price,
                    ),
                    realized_pnl=None,
                    tx_hash=tx_hash,
                    log_index=withdraw_index,
                ))

        return events
Пример #2
0
def test_add_and_get_yearn_vault_events(data_dir, username):
    """Test that get yearn vault events works fine and returns only events for what we need"""
    msg_aggregator = MessagesAggregator()
    data = DataHandler(data_dir, msg_aggregator)
    data.unlock(username, '123', create_new=True)

    addr1 = make_ethereum_address()
    addr1_events = [YearnVaultEvent(
        event_type='deposit',
        from_asset=A_DAI,
        from_value=Balance(amount=FVal(1), usd_value=FVal(1)),
        to_asset=Asset('yDAI'),
        to_value=Balance(amount=FVal(1), usd_value=FVal(1)),
        realized_pnl=None,
        block_number=1,
        timestamp=Timestamp(1),
        tx_hash='0x01653e88600a6492ad6e9ae2af415c990e623479057e4e93b163e65cfb2d4436',
        log_index=1,
    ), YearnVaultEvent(
        event_type='withdraw',
        from_asset=Asset('yDAI'),
        from_value=Balance(amount=FVal(1), usd_value=FVal(1)),
        to_asset=A_DAI,
        to_value=Balance(amount=FVal(1), usd_value=FVal(1)),
        realized_pnl=Balance(amount=FVal('0.01'), usd_value=FVal('0.01')),
        block_number=2,
        timestamp=Timestamp(2),
        tx_hash='0x4147da3e5d3c0565a99192ce0b32182ab30b8e1067921d9b2a8ef3bd60b7e2ce',
        log_index=2,
    )]
    data.db.add_yearn_vaults_events(address=addr1, events=addr1_events)
    addr2 = make_ethereum_address()
    addr2_events = [YearnVaultEvent(
        event_type='deposit',
        from_asset=A_DAI,
        from_value=Balance(amount=FVal(1), usd_value=FVal(1)),
        to_asset=Asset('yDAI'),
        to_value=Balance(amount=FVal(1), usd_value=FVal(1)),
        realized_pnl=None,
        block_number=1,
        timestamp=Timestamp(1),
        tx_hash='0x8c094d58f33e8dedcd348cb33b58f3bd447602f1fecb99e51b1c2868029eab55',
        log_index=1,
    ), YearnVaultEvent(
        event_type='withdraw',
        from_asset=Asset('yDAI'),
        from_value=Balance(amount=FVal(1), usd_value=FVal(1)),
        to_asset=A_DAI,
        to_value=Balance(amount=FVal(1), usd_value=FVal(1)),
        realized_pnl=Balance(amount=FVal('0.01'), usd_value=FVal('0.01')),
        block_number=2,
        timestamp=Timestamp(2),
        tx_hash='0x58c67445d26679623f9b7d56a8be260a275cb6744a1c1ae5a8d6883a5a5c03de',
        log_index=2,
    )]
    data.db.add_yearn_vaults_events(address=addr2, events=addr2_events)

    events = data.db.get_yearn_vaults_events(address=addr1, vault=YEARN_VAULTS['yDAI'])
    assert events == addr1_events
    events = data.db.get_yearn_vaults_events(address=addr2, vault=YEARN_VAULTS['yDAI'])
    assert events == addr2_events
Пример #3
0
    def _process_event(
        self,
        events: List[Dict[str, Any]],
        event_type: Literal['deposit', 'withdraw'],
    ) -> List[YearnVaultEvent]:
        result = []

        for entry in events:
            # The id returned is a composition of hash + '-' + log_index
            try:
                _, tx_hash, log_index, _ = entry['id'].split('-')
            except ValueError as e:
                log.debug(
                    f'Failed to extract transaction hash and log index from {event_type} event '
                    f'in yearn vaults v2 graph query. Got {entry["id"]}. {str(e)}.',
                )
                self.msg_aggregator.add_warning(
                    f'Ignoring {event_type} in yearn vault V2. Failed to read id {entry["id"]}',
                )
                continue

            try:
                if event_type == 'deposit':
                    from_asset = EthereumToken(entry['vault']['token']['id'])
                    to_asset = EthereumToken(
                        entry['vault']['shareToken']['id'])
                elif event_type == 'withdraw':
                    from_asset = EthereumToken(
                        entry['vault']['shareToken']['id'])
                    to_asset = EthereumToken(entry['vault']['token']['id'])
            except UnknownAsset:
                if event_type == 'deposit':
                    from_str = entry['vault']['token']['symbol']
                    to_str = entry['vault']['shareToken']['symbol']
                elif event_type == 'withdraw':
                    from_str = entry['vault']['shareToken']['symbol']
                    to_str = entry['vault']['token']['symbol']
                self.msg_aggregator.add_warning(
                    f'Ignoring {event_type} in yearn vaults V2 from {from_str} to '
                    f'{to_str} because the token is not recognized.', )
                continue
            except KeyError as e:
                log.debug(
                    f'Failed to extract token information from {event_type} event '
                    f'in yearn vaults v2 graph query. {str(e)}.', )
                self.msg_aggregator.add_warning(
                    f'Ignoring {event_type} {tx_hash} in yearn vault V2 Failed to decode'
                    f' remote information. ', )
                continue

            try:
                from_asset_usd_price = get_usd_price_zero_if_error(
                    asset=from_asset,
                    time=Timestamp(int(entry['timestamp']) // 1000),
                    location=f'yearn vault v2 deposit {tx_hash}',
                    msg_aggregator=self.msg_aggregator,
                )
                to_asset_usd_price = get_usd_price_zero_if_error(
                    asset=to_asset,
                    time=Timestamp(int(entry['timestamp']) // 1000),
                    location=f'yearn v2 vault deposit {tx_hash}',
                    msg_aggregator=self.msg_aggregator,
                )
                if event_type == 'deposit':
                    from_asset_amount = token_normalized_value(
                        token_amount=int(entry['tokenAmount']),
                        token=from_asset,
                    )
                    to_asset_amount = token_normalized_value(
                        token_amount=int(entry['sharesMinted']),
                        token=to_asset,
                    )
                elif event_type == 'withdraw':
                    from_asset_amount = token_normalized_value(
                        token_amount=int(entry['sharesBurnt']),
                        token=from_asset,
                    )
                    to_asset_amount = token_normalized_value(
                        token_amount=int(entry['tokenAmount']),
                        token=to_asset,
                    )
                result.append(
                    YearnVaultEvent(
                        event_type=event_type,
                        block_number=int(entry['blockNumber']),
                        timestamp=Timestamp(int(entry['timestamp']) // 1000),
                        from_asset=from_asset,
                        from_value=Balance(
                            amount=from_asset_amount,
                            usd_value=from_asset_amount * from_asset_usd_price,
                        ),
                        to_asset=to_asset,
                        to_value=Balance(
                            amount=to_asset_amount,
                            usd_value=to_asset_amount * to_asset_usd_price,
                        ),
                        realized_pnl=None,
                        tx_hash=tx_hash,
                        log_index=int(log_index),
                        version=2,
                    ))
            except (KeyError, ValueError) as e:
                msg = str(e)
                if isinstance(e, KeyError):
                    msg = f'Missing key entry for {msg}.'
                log.error(
                    f'Failed to read {event_type} from yearn vaults v2 graph because the response'
                    f' does not have the expected output.',
                    error=msg,
                )
                self.msg_aggregator.add_warning(
                    f'Ignoring {event_type} {tx_hash} in yearn vault V2 from {from_asset} to '
                    f'{to_asset} because the remote information is not correct.',
                )
                continue
        return result