def _get_liquidation_events( self, address: ChecksumEthAddress, from_ts: Timestamp, to_ts: Timestamp, ) -> List[CompoundEvent]: """https://compound.finance/docs/ctokens#liquidate-borrow""" param_types, param_values = get_common_params(from_ts, to_ts, address) result = self.graph.query( # type: ignore querystr= """liquidationEvents (where: {blockTime_lte: $end_ts, blockTime_gte: $start_ts, from: $address}) { id amount from blockNumber blockTime cTokenSymbol underlyingSymbol underlyingRepayAmount }}""", param_types=param_types, param_values=param_values, ) events = [] for entry in result['liquidationEvents']: ctoken_symbol = entry['cTokenSymbol'] try: ctoken_asset = Asset(ctoken_symbol) except UnknownAsset: log.error( f'Found unexpected cTokenSymbol {ctoken_symbol} during graph query. Skipping.' ) continue underlying_symbol = entry['underlyingSymbol'] try: underlying_asset = Asset(underlying_symbol) except UnknownAsset: log.error( f'Found unexpected token symbol {underlying_symbol} during ' f'graph query. Skipping.', ) continue timestamp = entry['blockTime'] # Amount/value of underlying asset paid by liquidator # Essentially liquidator covers part of the debt of the user debt_amount = FVal(entry['underlyingRepayAmount']) underlying_usd_price = query_usd_price_zero_if_error( asset=underlying_asset, time=timestamp, location='compound liquidation underlying asset', msg_aggregator=self.msg_aggregator, ) debt_usd_value = debt_amount * underlying_usd_price # Amount/value of ctoken_asset lost to the liquidator # This is what the liquidator gains at a discount liquidated_amount = FVal(entry['amount']) liquidated_usd_price = query_usd_price_zero_if_error( asset=ctoken_asset, time=timestamp, location='compound liquidation ctoken asset', msg_aggregator=self.msg_aggregator, ) liquidated_usd_value = liquidated_amount * liquidated_usd_price parse_result = _get_txhash_and_logidx(entry['id']) if parse_result is None: log.error( f'Found unprocessable liquidation id from the graph {entry["id"]}. Skipping', ) continue gained_value = Balance(amount=debt_amount, usd_value=debt_usd_value) lost_value = Balance(amount=liquidated_amount, usd_value=liquidated_usd_value) events.append( CompoundEvent( event_type='liquidation', address=address, block_number=entry['blockNumber'], timestamp=timestamp, asset=underlying_asset, value=gained_value, to_asset=ctoken_asset, to_value=lost_value, realized_pnl=None, tx_hash=parse_result[0], log_index=parse_result[1], )) return events
def _get_lend_events( self, event_type: Literal['mint', 'redeem'], address: ChecksumEthAddress, from_ts: Timestamp, to_ts: Timestamp, ) -> List[CompoundEvent]: param_types, param_values = get_common_params(from_ts, to_ts, address) if event_type == 'mint': graph_event_name = 'mintEvents' addr_position = 'to' elif event_type == 'redeem': graph_event_name = 'redeemEvents' addr_position = 'from' result = self.graph.query( # type: ignore querystr=LEND_EVENTS_QUERY_PREFIX.format( graph_event_name=graph_event_name, addr_position=addr_position, ), param_types=param_types, param_values=param_values, ) events = [] for entry in result[graph_event_name]: ctoken_symbol = entry['cTokenSymbol'] try: ctoken_asset = Asset(ctoken_symbol) except UnknownAsset: log.error( f'Found unexpected cTokenSymbol {ctoken_symbol} during graph query. Skipping.' ) continue underlying_symbol = ctoken_symbol[1:] try: underlying_asset = Asset(underlying_symbol) except UnknownAsset: log.error( f'Found unexpected token symbol {underlying_symbol} during ' f'graph query. Skipping.', ) continue timestamp = entry['blockTime'] usd_price = query_usd_price_zero_if_error( asset=underlying_asset, time=timestamp, location=f'compound {event_type}', msg_aggregator=self.msg_aggregator, ) underlying_amount = FVal(entry['underlyingAmount']) usd_value = underlying_amount * usd_price parse_result = _get_txhash_and_logidx(entry['id']) if parse_result is None: log.error( f'Found unprocessable mint id from the graph {entry["id"]}. Skipping' ) continue amount = FVal(entry['amount']) if event_type == 'mint': from_value = Balance(amount=underlying_amount, usd_value=usd_value) to_value = Balance(amount=amount, usd_value=usd_value) from_asset = underlying_asset to_asset = ctoken_asset else: # redeem from_value = Balance(amount=amount, usd_value=usd_value) to_value = Balance(amount=underlying_amount, usd_value=usd_value) from_asset = ctoken_asset to_asset = underlying_asset events.append( CompoundEvent( event_type=event_type, address=address, block_number=entry['blockNumber'], timestamp=timestamp, asset=from_asset, value=from_value, to_asset=to_asset, to_value=to_value, realized_pnl=None, tx_hash=parse_result[0], log_index=parse_result[1], )) return events
def _get_borrow_events( self, event_type: Literal['borrow', 'repay'], address: ChecksumEthAddress, from_ts: Timestamp, to_ts: Timestamp, ) -> List[CompoundEvent]: param_types, param_values = get_common_params(from_ts, to_ts, address) if event_type == 'borrow': graph_event_name = 'borrowEvents' payer_or_empty = '' elif event_type == 'repay': graph_event_name = 'repayEvents' payer_or_empty = 'payer' result = self.graph.query( # type: ignore querystr=BORROW_EVENTS_QUERY_PREFIX.format( graph_event_name=graph_event_name, payer_or_empty=payer_or_empty, ), param_types=param_types, param_values=param_values, ) events = [] for entry in result[graph_event_name]: underlying_symbol = entry['underlyingSymbol'] try: underlying_asset = Asset(underlying_symbol) except UnknownAsset: log.error( f'Found unexpected token symbol {underlying_symbol} during ' f'graph query. Skipping.', ) continue timestamp = entry['blockTime'] usd_price = query_usd_price_zero_if_error( asset=underlying_asset, time=timestamp, location=f'compound {event_type}', msg_aggregator=self.msg_aggregator, ) amount = FVal(entry['amount']) parse_result = _get_txhash_and_logidx(entry['id']) if parse_result is None: log.error( f'Found unprocessable borrow/repay id from the graph {entry["id"]}. Skipping', ) continue events.append( CompoundEvent( event_type=event_type, address=address, block_number=entry['blockNumber'], timestamp=timestamp, asset=underlying_asset, value=Balance(amount=amount, usd_value=amount * usd_price), to_asset=None, to_value=None, realized_pnl=None, tx_hash=parse_result[0], log_index=parse_result[1], )) return events