Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add missing models to Transformzklend #278

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions apps/data_handler/handler_tools/data_parser/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ def validate_addresses(cls, value: str) -> str:
return add_leading_zeros(value)

@field_validator("amount", mode="before")
def validate_amount(cls, value: str) -> Decimal:
def validate_amount(cls, value: str, info: ValidationInfo) -> Decimal:
"""
Validates that the provided amount is numeric and converts it to a Decimal.

Expand All @@ -308,10 +308,13 @@ def validate_amount(cls, value: str) -> Decimal:
Raises:
ValueError: If the provided amount is not numeric.
"""
if not value.isdigit():
raise ValueError("Amount field is not numeric")
return Decimal(value)

try:
return Decimal(int(value, 16))
except ValueError:
raise ValueError(
f"{info.field_name} field is not a valid hexadecimal number"
)


class CollateralEnabledDisabledEventData(BaseModel):
""" Data model representing a collateral enabled/disabled event in the system. """
Expand All @@ -329,4 +332,4 @@ def validate_valid_addresses(cls, value: str, info: ValidationInfo) -> str:
"""
if not value.startswith("0x"):
raise ValueError("Invalid address provided for %s" % info.field_name)
return add_leading_zeros(value)
return add_leading_zeros(value)
6 changes: 3 additions & 3 deletions apps/data_handler/handler_tools/data_parser/zklend.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,6 @@ def parse_collateral_enabled_disabled_event(
CollateralEnabledDisabledEventData: A model with the parsed event data.
"""
return CollateralEnabledDisabledEventData(
user=event_data["data"][0],
token=event_data["data"][1],
)
user=event_data[0],
token=event_data[1],
)
214 changes: 180 additions & 34 deletions apps/data_handler/handlers/events/zklend/transform_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,87 @@
from typing import Dict, Any, Tuple, Type, Callable
from shared.constants import ProtocolIDs
from data_handler.handler_tools.data_parser.zklend import ZklendDataParser
from data_handler.db.models.zklend_events import (
AccumulatorsSyncEventModel,
LiquidationEventModel,

from data_handler.handler_tools.data_parser.serializers import (
AccumulatorsSyncEventData,
LiquidationEventData,
WithdrawalEventData,
BorrowingEventData,
RepaymentEventData,
DepositEventData,
CollateralEnabledDisabledEventData,
)

from data_handler.db.crud import ZkLendEventDBConnector
from data_handler.handler_tools.constants import ProtocolAddresses




logger = logging.getLogger(__name__)

EVENT_MAPPING: Dict[str, Tuple[Callable, str, Type[Base]]] = {
EVENT_MAPPING: Dict[str, Tuple[Callable, str]] = {
"AccumulatorsSync": (
ZklendDataParser.parse_accumulators_sync_event,
"create_accumulator_event",
AccumulatorsSyncEventModel
),
"Liquidation": (
ZklendDataParser.parse_liquidation_event,
"create_liquidation_event",
LiquidationEventModel
"save_accumulators_sync_event"
),
"zklend::market::Market::AccumulatorsSync": (
ZklendDataParser.parse_accumulators_sync_event,
"create_accumulator_event",
AccumulatorsSyncEventModel
"save_accumulators_sync_event"
),
"Liquidation": (
ZklendDataParser.parse_liquidation_event,
"save_liquidation_event"
),
"zklend::market::Market::Liquidation": (
ZklendDataParser.parse_liquidation_event,
"create_liquidation_event",
LiquidationEventModel
"save_liquidation_event"
),
"Repayment": (
ZklendDataParser.parse_repayment_event,
"save_repayment_event"
),
"zklend::market::Market::Repayment": (
ZklendDataParser.parse_repayment_event,
"save_repayment_event"
),
"Borrowing": (
ZklendDataParser.parse_borrowing_event,
"save_borrowing_event"
),
"zklend::market::Market::Borrowing": (
ZklendDataParser.parse_borrowing_event,
"save_borrowing_event"
),
"Deposit": (
ZklendDataParser.parse_deposit_event,
"save_deposit_event"
),
"zklend::market::Market::Deposit": (
ZklendDataParser.parse_deposit_event,
"save_deposit_event"
),
"Withdrawal": (
ZklendDataParser.parse_withdrawal_event,
"save_withdrawal_event"
),
"zklend::market::Market::Withdrawal": (
ZklendDataParser.parse_withdrawal_event,
"save_withdrawal_event"
),
"CollateralEnabled": (
ZklendDataParser.parse_collateral_enabled_disabled_event,
"save_collateral_enabled_disabled_event"
),
"zklend::market::Market::CollateralEnabled": (
ZklendDataParser.parse_collateral_enabled_disabled_event,
"save_collateral_enabled_disabled_event"
),
"CollateralDisabled": (
ZklendDataParser.parse_collateral_enabled_disabled_event,
"save_collateral_enabled_disabled_event"
),
"zklend::market::Market::CollateralDisabled": (
ZklendDataParser.parse_collateral_enabled_disabled_event,
"save_collateral_enabled_disabled_event"
),
}

Expand All @@ -50,8 +99,8 @@ class ZklendTransformer:
A class that is used to transform Zklend events into database models.
"""

EVENT_MAPPING: Dict[str, Tuple[Callable, Type[BaseModel], Type[Base]]] = EVENT_MAPPING
PROTOCOL_ADDRESSES: str = ProtocolAddresses.ZKLEND_MARKET_ADDRESSES
EVENT_MAPPING: Dict[str, Tuple[Callable, str, Type[Base]]] = EVENT_MAPPING
PROTOCOL_ADDRESSES: str = "0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05"
djeck1432 marked this conversation as resolved.
Show resolved Hide resolved
PROTOCOL_TYPE: ProtocolIDs = ProtocolIDs.ZKLEND
PAGINATION_SIZE: int = 1000

Expand Down Expand Up @@ -82,31 +131,127 @@ def fetch_and_transform_events(self, from_address: str, min_block: int, max_bloc
for event in response:
event_type = event.get("key_name")
if event_type in self.EVENT_MAPPING:
parser_func, method_name, model_class = self.EVENT_MAPPING[event_type]
parser_func, save_to_db_method_name = self.EVENT_MAPPING[event_type]
parsed_data = parser_func(event["data"])
db_model = model_class(**parsed_data.model_dump())
self.db_connector[method_name](db_model)

getattr(self, save_to_db_method_name)(
event_name=event_type,
block_number=event.get("block_number"),
event_data=parsed_data
)
else:
logger.info(f"Event type {event_type} not supported, yet...")

def save_accumulators_sync_event(self, event: Dict[str, Any]) -> None:
def save_accumulators_sync_event(self, event_name: str, block_number: int, event_data: AccumulatorsSyncEventData) -> None:
"""
Save an accumulators sync event to the database.
"""
parser_func, _, model_class = self.EVENT_MAPPING["zklend::market::Market::AccumulatorsSync"]
parsed_data = parser_func(event)
db_model = model_class(**parsed_data.model_dump())
self.db_connector.create_accumulator_event(db_model)
self.db_connector.create_accumulator_event(
protocol_id=self.PROTOCOL_TYPE,
event_name=event_name,
block_number=block_number,
event_data={
"token": event_data.token,
"lending_accumulator": event_data.lending_accumulator,
"debt_accumulator": event_data.debt_accumulator
}
)

def save_liquidation_event(self, event: Dict[str, Any]) -> None:
def save_liquidation_event(self, event_name: str, block_number: int, event_data: LiquidationEventData) -> None:
"""
Save a liquidation event to the database.
"""
parser_func, _, model_class = self.EVENT_MAPPING["zklend::market::Market::Liquidation"]
parsed_data = parser_func(event)
db_model = model_class(**parsed_data.model_dump())

self.db_connector.create_liquidation_event(db_model)
self.db_connector.create_liquidation_event(
protocol_id=self.PROTOCOL_TYPE,
event_name=event_name,
block_number=block_number,
event_data={
"liquidator": event_data.liquidator,
"user": event_data.user,
"debt_token": event_data.debt_token,
"debt_raw_amount": event_data.debt_raw_amount,
"debt_face_amount": event_data.debt_face_amount,
"collateral_token": event_data.collateral_token,
"collateral_amount": event_data.collateral_amount
}
)

def save_borrowing_event(self, event_name: str, block_number: int, event_data: BorrowingEventData) -> None:
"""
Save a borrowing event to the database.
"""
self.db_connector.create_borrowing_event(
protocol_id=self.PROTOCOL_TYPE,
event_name=event_name,
block_number=block_number,
event_data={
"user": event_data.user,
"token": event_data.token,
"raw_amount": event_data.raw_amount,
"face_amount": event_data.face_amount
}
)

def save_deposit_event(self, event_name: str, block_number: int, event_data: DepositEventData) -> None:
"""
Save a deposit event to the database.
"""
self.db_connector.create_deposit_event(
protocol_id=self.PROTOCOL_TYPE,
event_name=event_name,
block_number=block_number,
event_data={
"user": event_data.user,
"token": event_data.token,
"face_amount": event_data.face_amount
}
)

def save_withdrawal_event(self, event_name: str, block_number: int, event_data: WithdrawalEventData) -> None:
"""
Save a withdrawal event to the database.
"""
self.db_connector.create_withdrawal_event(
protocol_id=self.PROTOCOL_TYPE,
event_name=event_name,
block_number=block_number,
event_data={
"user": event_data.user,
"token": event_data.token,
"amount": event_data.amount
}
)

def save_collateral_enabled_disabled_event(self, event_name: str, block_number: int, event_data: CollateralEnabledDisabledEventData) -> None:
"""
Save a collateral enabled/disabled event to the database.
"""
self.db_connector.create_collateral_enabled_disabled_event(
protocol_id=self.PROTOCOL_TYPE,
event_name=event_name,
block_number=block_number,
event_data={
"user": event_data.user,
"token": event_data.token
}
)

def save_repayment_event(self, event_name: str, block_number: int, event_data: RepaymentEventData) -> None:
"""
Save a repayment event to the database.
"""
self.db_connector.create_repayment_event(
djeck1432 marked this conversation as resolved.
Show resolved Hide resolved
protocol_id=self.PROTOCOL_TYPE,
event_name=event_name,
block_number=block_number,
event_data={
"repayer": event_data.repayer,
"beneficiary": event_data.beneficiary,
"token": event_data.token,
"raw_amount": event_data.raw_amount,
"face_amount": event_data.face_amount
}
)

def run(self) -> None:
"""
Expand All @@ -131,4 +276,5 @@ def run(self) -> None:
This is the init function for when ZklendTransformer class is called directly.
"""
transformer = ZklendTransformer()
transformer.run()
transformer.run()

29 changes: 28 additions & 1 deletion apps/data_handler/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@
from unittest.mock import MagicMock

import pytest
from data_handler.db.crud import DBConnector, InitializerDBConnector
from data_handler.db.crud import (
DBConnector,
InitializerDBConnector,
ZkLendEventDBConnector
)
from data_handler.handler_tools.api_connector import DeRiskAPIConnector
from data_handler.handler_tools.data_parser.zklend import ZklendDataParser


@pytest.fixture(scope="module")
def mock_db_connector() -> None:
Expand Down Expand Up @@ -36,3 +42,24 @@ def mock_api_connector():
"""
mock_api_connector = MagicMock(spec=DeRiskAPIConnector)
yield mock_api_connector


@pytest.fixture(scope="function")
def mock_zklend_event_db_connector():
"""
Mock for ZkLendEventDBConnector
:return: None
"""
mock_zklend_event_db_connector = MagicMock(spec=ZkLendEventDBConnector)
yield mock_zklend_event_db_connector


@pytest.fixture(scope="function")
def mock_zklend_data_parser():
"""
Mock for ZklendDataParser
:return: None
"""
mock_zklend_data_parser = MagicMock(spec=ZklendDataParser)
yield mock_zklend_data_parser
k
Loading