Skip to content

Commit

Permalink
feat: standardize event data for mint and burn non-interest
Browse files Browse the repository at this point in the history
  • Loading branch information
Tzienom committed Nov 23, 2024
1 parent 516be74 commit ae6391e
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 113 deletions.
87 changes: 44 additions & 43 deletions apps/data_handler/handler_tools/data_parser/nostra.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,73 +5,74 @@
from data_handler.handler_tools.data_parser.serializers import (
DebtMintEventData,
DebtBurnEventData,
InterestRateModelEventData,
DebtTransferEventData,
NonInterestBearingCollateralMintEventData,
NonInterestBearingCollateralBurnEventData
)


class NostraDataParser:
"""
Parses the nostra data to human-readable format.
"""
def parse_interest_rate_model_event(
cls, event_data: List[Any]
) -> InterestRateModelEventData:
def parse_interest_rate_model_event(self):
pass

@classmethod
def parse_non_interest_bearing_collateral_mint_event(
cls, event_data: list[Any]
) -> NonInterestBearingCollateralMintEventData:
"""
Parses the interest rate model event data into a human-readable format.
Parses the non-interest bearing collateral mint event data into a human-readable format.
The event data is fetched from on-chain logs and is structured in the following way:
- event_data[0]: The debt token address (as a hexadecimal string).
- event_data[5]: The lending interest rate index (as a hexadecimal in 18 decimal places).
- event_data[7]: The borrow interest rate index (as a hexadecimal in 18 decimal places).
The event data is structured as follows:
- event_data[0]: sender address
- event_data[1]: recipient address
- event_data[2]: raw amount
Args:
event_data (List[Any]): A list containing the raw event data.
Expected order: [debt_token, lending_rate, _, borrow_rate, _,
lending_index, _, borrow_index, _]
event_data (list[Any]): A list containing the raw event data with 3 elements:
sender, recipient, and raw amount.
Returns:
InterestRateModelEventData: A model with the parsed event data.
NonInterestBearingCollateralMintEventData: A model with the parsed event data.
"""
return InterestRateModelEventData(
debt_token=event_data[0],
lending_index=event_data[5],
borrow_index=event_data[7]
return NonInterestBearingCollateralMintEventData(
sender=event_data[0],
recipient=event_data[1],
raw_amount=event_data[2]
)

def parse_non_interest_bearing_collateral_mint_event(self):
pass
@classmethod
def parse_non_interest_bearing_collateral_burn_event(
cls, event_data: list[Any]
) -> NonInterestBearingCollateralBurnEventData:
"""
Parses the non-interest bearing collateral burn event data into a human-readable format.
def parse_non_interest_bearing_collateral_burn_event(self):
pass
The event data is structured as follows:
- event_data[0]: user address
- event_data[1]: face amount
Args:
event_data (list[Any]): A list containing the raw event data with 2 elements:
user and face amount.
Returns:
NonInterestBearingCollateralBurnEventData: A model with the parsed event data.
"""
return NonInterestBearingCollateralBurnEventData(
user=event_data[0],
face_amount=event_data[1]
)

def parse_interest_bearing_collateral_mint_event(self):
pass

def parse_interest_bearing_collateral_burn_event(self):
pass

def parse_debt_transfer_event(
cls, event_data: List[Any], from_address: str
) -> DebtTransferEventData:
"""
Parses the debt transfer event data into a human-readable format using the
DebtBurnEventData serializer.
Args:
event_data (List[Any]): A list containing the raw event data.
Expected order: [sender, recipient, value, _]
from_address (str): The address of the token contract
Returns:
DebtTransferEventData: A model with the parsed event data.
"""
return DebtTransferEventData(
sender=event_data[0],
recipient=event_data[1],
amount=event_data[2],
token=from_address
)
def parse_debt_transfer_event(self):
pass

def parse_debt_mint_event(self, event_data: list[Any]) -> DebtMintEventData:
"""
Expand Down
96 changes: 64 additions & 32 deletions apps/data_handler/handler_tools/data_parser/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,74 +445,106 @@ def validate_numeric_string(cls, value: str, info: ValidationInfo) -> Decimal:
raise ValueError(
f"{info.field_name} field is not a valid hexadecimal number"
)

class InterestRateModelEventData(BaseModel):
class NonInterestBearingCollateralMintEventData(BaseModel):
"""
Data model representing an interest rate model event in the Nostra protocol.
Serializer for non-interest bearing collateral mint event data.
Attributes:
debt_token (str): The address of the debt token.
lending_index (Decimal): The lending index in hexadecimal.
borrow_index (Decimal): The borrow index in hexadecimal.
sender (str): The address of the sender
recipient (str): The address of the recipient
raw_amount (str): The raw amount being transferred
"""
debt_token: str
lending_index: Decimal
borrow_index: Decimal

@field_validator("debt_token")
sender: str
recipient: str
raw_amount: str
@field_validator("sender", "recipient")
def validate_address(cls, value: str, info: ValidationInfo) -> str:
"""
Validates and formats the token address.
Validates that the provided address starts with '0x' and
formats it with leading zeros.
Args:
value (str): The address string to validate.
Returns:
str: The validated and formatted address.
Raises:
ValueError: If the provided address does not start with '0x'.
"""
if not value.startswith("0x"):
raise ValueError(f"Invalid address provided for {info.field_name}")
return add_leading_zeros(value)

@field_validator("lending_index", "borrow_index")
@field_validator("raw_amount")
def validate_numeric_string(cls, value: str, info: ValidationInfo) -> Decimal:
"""
Converts a hexadecimal string to a Decimal.
Validates that the provided value is numeric, and converts it to a proper Decimal number.
Validates that the provided amount is numeric and converts it to a Decimal.
Args:
value (str): The amount string to validate.
Returns:
Decimal: The validated and converted amount as a Decimal.
Raises:
ValueError: If the provided amount is not numeric.
"""
try:
return Decimal(int(value, 16)) / Decimal("1e18")
return Decimal(int(value, 16))
except ValueError:
raise ValueError(
f"{info.field_name} field is not a valid hexadecimal number"
)

class DebtTransferEventData(BaseModel):
class NonInterestBearingCollateralBurnEventData(BaseModel):
"""
Data model representing a debt transfer event.
Serializer for non-interest bearing collateral burn event data.
Attributes:
sender (str): Address of the sender.
recipient (str): Address of the recipient.
amount (str): Transfer amount in hexadecimal.
token (str): Address of the debt token.
user (str): The address of the user
face_amount (str): The face amount being burned
"""
sender: str
recipient: str
amount: Decimal

@field_validator("sender", "recipient")
user: str
face_amount: str
@field_validator("user")
def validate_address(cls, value: str, info: ValidationInfo) -> str:
"""
Validates and formats the address.
Validates that the provided address starts with '0x' and
formats it with leading zeros.
Args:
value (str): The address string to validate.
Returns:
str: The validated and formatted address.
Raises:
ValueError: If the provided address does not start with '0x'.
"""
if not value.startswith("0x"):
raise ValueError(f"Invalid address provided for {info.field_name}")
return add_leading_zeros(value)

@field_validator("amount")
@field_validator("face_amount")
def validate_numeric_string(cls, value: str, info: ValidationInfo) -> Decimal:
"""
Validates that the provided amount is numeric and converts it to a Decimal.
Args:
value (str): The amount string to validate.
Returns:
Decimal: The validated and converted amount as a Decimal.
Raises:
ValueError: If the provided amount is not numeric.
"""
try:
return Decimal(int(value, 16))
except ValueError:
raise ValueError(
f"{info.field_name} field is not a valid hexadecimal number"
)

72 changes: 34 additions & 38 deletions apps/data_handler/handlers/loan_states/nostra_alpha/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,16 +340,16 @@ def process_interest_rate_model_event(self, event: pd.Series) -> None:
# `lendIndex`, ``, `borrowIndex`, ``.
# Example:
# https://starkscan.co/event/0x05e95588e281d7cab6f89aa266057c4c9bcadf3ff0bb85d4feea40a4faa94b09_4.
# Parse the event using the new serializer
data = NostraDataParser.parse_interest_rate_model_event(event["data"])
debt_token = parsed_event_data.debt_token
collateral_interest_rate_index = parsed_event_data.lending_index
debt_interest_rate_index = parsed_event_data.borrow_index
debt_token = add_leading_zeros(event["data"][0])
collateral_interest_rate_index = decimal.Decimal(str(int(event["data"][5], base=16))
) / decimal.Decimal("1e18")
debt_interest_rate_index = decimal.Decimal(str(int(event["data"][7], base=16))
) / decimal.Decimal("1e18")
else:
raise ValueError("Event = {} has an unexpected structure.".format(event))

collateral_token = self.debt_token_addresses_to_interest_bearing_collateral_token_addresses.get(
debt_token, None)
debt_token, None
)
# The indices are saved under the respective collateral or debt token address.
if collateral_token:
self.interest_rate_models.collateral[collateral_token] = (
Expand All @@ -369,32 +369,30 @@ def process_non_interest_bearing_collateral_mint_event(self, event: pd.Series) -
# `from_`, `to`, `value`, ``.
# Example:
# https://starkscan.co/event/0x06ddd34767c8cef97d4508bcbb4e3771b1c93e160e02ca942cadbdfa29ef9ba8_2.
sender = add_leading_zeros(event["data"][0])
recipient = add_leading_zeros(event["data"][1])
raw_amount = decimal.Decimal(str(int(event["data"][2], base=16)))
parsed_event = NostraDataParser.parse_non_interest_bearing_collateral_mint_event(event["data"])
else:
raise ValueError("Event = {} has an unexpected structure.".format(event))
if self.ZERO_ADDRESS in {sender, recipient}:
if self.ZERO_ADDRESS in {parsed_event.sender, parsed_event.recipient}:
return

token = add_leading_zeros(event["from_address"])
if sender != self.DEFERRED_BATCH_CALL_ADAPTER_ADDRESS:
self.loan_entities[sender].collateral.increase_value(token=token, value=-raw_amount)
self.loan_entities[sender].extra_info.block = event["block_number"]
self.loan_entities[sender].extra_info.timestamp = event["timestamp"]
if recipient != self.DEFERRED_BATCH_CALL_ADAPTER_ADDRESS:
self.loan_entities[recipient].collateral.increase_value(token=token, value=raw_amount)
self.loan_entities[recipient].extra_info.block = event["block_number"]
self.loan_entities[recipient].extra_info.timestamp = event["timestamp"]
if self.verbose_user in {sender, recipient}:
if parsed_event.sender != self.DEFERRED_BATCH_CALL_ADAPTER_ADDRESS:
self.loan_entities[parsed_event.sender].collateral.increase_value(token=token, value=-parsed_event.raw_amount)
self.loan_entities[parsed_event.sender].extra_info.block = event["block_number"]
self.loan_entities[parsed_event.sender].extra_info.timestamp = event["timestamp"]
if parsed_event.recipient != self.DEFERRED_BATCH_CALL_ADAPTER_ADDRESS:
self.loan_entities[parsed_event.recipient].collateral.increase_value(token=token, value=parsed_event.raw_amount)
self.loan_entities[parsed_event.recipient].extra_info.block = event["block_number"]
self.loan_entities[parsed_event.recipient].extra_info.timestamp = event["timestamp"]
if self.verbose_user in {parsed_event.sender, parsed_event.recipient}:
logging.info(
"In block number = {}, collateral of raw amount = {} of token = {} was transferred from user = {} to user = {}."
.format(
event["block_number"],
raw_amount,
parsed_event.raw_amount,
token,
sender,
recipient,
parsed_event.sender,
parsed_event.recipient,
)
)

Expand Down Expand Up @@ -463,10 +461,9 @@ def process_debt_transfer_event(self, event: pd.Series) -> None:
# `from_`, `to`, `value`, ``.
# Example:
# https://starkscan.co/event/0x0786a8918c8897db760899ee35b43071bfd723fec76487207882695e4b3014a0_1.
event_data = NostraDataParser.parse_debt_transfer_event(event["data"])
sender = event_data.sender
recipient = event_data.recipient
raw_amount = event_data.amount
sender = add_leading_zeros(event["data"][0])
recipient = add_leading_zeros(event["data"][1])
raw_amount = decimal.Decimal(str(int(event["data"][2], base=16)))
else:
raise ValueError("Event = {} has an unexpected structure.".format(event))
if self.ZERO_ADDRESS in {sender, recipient}:
Expand Down Expand Up @@ -499,27 +496,26 @@ def process_non_interest_bearing_collateral_burn_event(self, event: pd.Series) -
# The order of the values in the `data` column is: `user`, `amount`, ``.
# Example:
# https://starkscan.co/event/0x00744177ee88dd3d96dda1784e2dff50f0c989b7fd48755bc42972af2e951dd6_1.
user = event["data"][0]
if user == self.IGNORE_USER:
parsed_event = NostraDataParser.parse_non_interest_bearing_collateral_burn_event(event["data"])
if parsed_event.user == self.IGNORE_USER:
return
token = self.ADDRESSES_TO_TOKENS[event["from_address"]]
face_amount = decimal.Decimal(str(int(event["data"][1], base=16)))
raw_amount = face_amount / self.collateral_interest_rate_models.values[token]
raw_amount = parsed_event.face_amount / self.collateral_interest_rate_models.values[token]
# add additional info block and timestamp
self.loan_entities[user].extra_info.block = event["block_number"]
self.loan_entities[user].extra_info.timestamp = event["timestamp"]
self.loan_entities[parsed_event.user].extra_info.block = event["block_number"]
self.loan_entities[parsed_event.user].extra_info.timestamp = event["timestamp"]

self.loan_entities[user].non_interest_bearing_collateral.increase_value(
self.loan_entities[parsed_event.user].non_interest_bearing_collateral.increase_value(
token=token, value=-raw_amount
)
self.loan_entities[user].collateral.values = {
self.loan_entities[parsed_event.user].collateral.values = {
token: (
self.loan_entities[user].non_interest_bearing_collateral.values[token] +
self.loan_entities[user].interest_bearing_collateral.values[token]
self.loan_entities[parsed_event.user].non_interest_bearing_collateral.values[token] +
self.loan_entities[parsed_event.user].interest_bearing_collateral.values[token]
)
for token in NOSTRA_ALPHA_SPECIFIC_TOKEN_SETTINGS
}
if user == self.verbose_user:
if parsed_event.user == self.verbose_user:
logging.info(
"In block number = {}, non-interest-bearing collateral of raw amount = {} of token = {} was withdrawn."
.format(
Expand Down

0 comments on commit ae6391e

Please sign in to comment.