-
Notifications
You must be signed in to change notification settings - Fork 40
Implement apibara indexer #193
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
Changes from all commits
5c27e9c
fa2f0fa
7ab261f
f492aa9
65fc76b
5b39e73
3cc38e9
e29541c
3ae49f8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| import os | ||
|
|
||
| NETWORK = "starknet-sepolia" | ||
|
|
||
| SPHERRE_CONTRACT_ADDRESS = "" | ||
| SERVER_URL = "" | ||
| MONGO_URL = "" | ||
| DNA_TOKEN = os.environ.get("DNA_TOKEN") | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| import asyncio | ||
| from functools import wraps | ||
|
|
||
| import click | ||
|
|
||
| from spherre.indexer.config import DNA_TOKEN, MONGO_URL, SERVER_URL | ||
| from spherre.indexer.service.indexers import run_main_indexer | ||
|
|
||
|
|
||
| def async_command(f): | ||
| @wraps(f) | ||
| def wrapper(*args, **kwargs): | ||
| return asyncio.run(f(*args, **kwargs)) | ||
|
|
||
| return wrapper | ||
|
|
||
|
|
||
| @click.group() | ||
| def cli(): | ||
| pass | ||
|
|
||
|
|
||
| @cli.command() | ||
| @click.option("--server-url", default=None, help="Apibara stream url.") | ||
| @click.option("--mongo-url", default=None, help="MongoDB url.") | ||
| @click.option("--restart", is_flag=True, help="Restart indexing from the beginning.") | ||
| @async_command | ||
| async def start(server_url, mongo_url, restart): | ||
| """Start the indexer.""" | ||
| if server_url is None: | ||
| server_url = SERVER_URL | ||
| if mongo_url is None: | ||
| mongo_url = MONGO_URL | ||
|
|
||
| print("Starting Apibara indexer...") | ||
| print(f"Server url: {server_url}") | ||
| await run_main_indexer( | ||
| restart=restart, | ||
| server_url=server_url, | ||
| mongo_url=mongo_url, | ||
| dna_token=DNA_TOKEN, | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| from typing import Callable, Dict | ||
|
|
||
| from spherre.indexer.service.types import ( | ||
| AccountCreationEvent, | ||
| BaseEventModel, | ||
| EventEnum, | ||
| ) | ||
|
|
||
|
|
||
| class EventHandlers: | ||
| @classmethod | ||
| def handle_account_creation(cls, data: AccountCreationEvent): | ||
| pass | ||
|
|
||
| @classmethod | ||
| def handle_token_transafer(cls): | ||
| pass | ||
|
Comment on lines
+10
to
+17
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implement the handlers (and fix the typo). Both handlers are 🤖 Prompt for AI Agents |
||
|
|
||
|
|
||
| DATA_HANDLERS: Dict[EventEnum, Callable[[BaseEventModel], None]] = { | ||
| EventEnum.ACCOUNT_CREATION: EventHandlers.handle_account_creation, | ||
| EventEnum.TOKEN_TRANSFER: EventHandlers.handle_token_transafer, | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,137 @@ | ||||||||||||||||||||||||||||||||||||||||||
| from apibara.indexer import IndexerRunner, IndexerRunnerConfiguration, Info | ||||||||||||||||||||||||||||||||||||||||||
| from apibara.indexer.indexer import IndexerConfiguration | ||||||||||||||||||||||||||||||||||||||||||
| from apibara.protocol.proto.stream_pb2 import Cursor, DataFinality | ||||||||||||||||||||||||||||||||||||||||||
| from apibara.starknet import EventFilter, Filter, StarkNetIndexer, felt | ||||||||||||||||||||||||||||||||||||||||||
| from apibara.starknet.cursor import starknet_cursor | ||||||||||||||||||||||||||||||||||||||||||
| from apibara.starknet.proto.starknet_pb2 import Block | ||||||||||||||||||||||||||||||||||||||||||
| from loguru import logger | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| from spherre.indexer.config import NETWORK, SPHERRE_CONTRACT_ADDRESS | ||||||||||||||||||||||||||||||||||||||||||
| from spherre.indexer.service.event_handlers import DATA_HANDLERS | ||||||||||||||||||||||||||||||||||||||||||
| from spherre.indexer.service.types import ( | ||||||||||||||||||||||||||||||||||||||||||
| EVENT_SELECTORS, | ||||||||||||||||||||||||||||||||||||||||||
| EventEnum, | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
| from spherre.indexer.service.utils import DATA_TRANSFORMERS | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| class SpherreMainIndexer(StarkNetIndexer): | ||||||||||||||||||||||||||||||||||||||||||
| def start_account_indexer(self, address: str): | ||||||||||||||||||||||||||||||||||||||||||
| # create a new filter for the account address | ||||||||||||||||||||||||||||||||||||||||||
| account_address = felt.from_hex(address) | ||||||||||||||||||||||||||||||||||||||||||
| filter = ( | ||||||||||||||||||||||||||||||||||||||||||
| EventFilter() | ||||||||||||||||||||||||||||||||||||||||||
| .with_from_address(account_address) | ||||||||||||||||||||||||||||||||||||||||||
| .with_keys([EVENT_SELECTORS.values()]) | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
| # add the filter to the indexer | ||||||||||||||||||||||||||||||||||||||||||
| self.update_filter(filter) | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+19
to
+28
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Convert dict values view to list. Line 27: Apply this diff: filter = (
EventFilter()
.with_from_address(account_address)
- .with_keys([EVENT_SELECTORS.values()])
+ .with_keys(list(EVENT_SELECTORS.values()))
)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| def indexer_id(self) -> str: | ||||||||||||||||||||||||||||||||||||||||||
| return "spherre" | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| def initial_configuration(self) -> Filter: | ||||||||||||||||||||||||||||||||||||||||||
| # Return initial configuration of the indexer. | ||||||||||||||||||||||||||||||||||||||||||
| address = felt.from_hex(SPHERRE_CONTRACT_ADDRESS) | ||||||||||||||||||||||||||||||||||||||||||
| return IndexerConfiguration( | ||||||||||||||||||||||||||||||||||||||||||
| filter=Filter().add_event( | ||||||||||||||||||||||||||||||||||||||||||
| EventFilter() | ||||||||||||||||||||||||||||||||||||||||||
| .with_from_address(address) | ||||||||||||||||||||||||||||||||||||||||||
| .with_keys([EVENT_SELECTORS[EventEnum.ACCOUNT_CREATION]]) | ||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||
| starting_cursor=starknet_cursor(10_000), | ||||||||||||||||||||||||||||||||||||||||||
| finality=DataFinality.DATA_STATUS_ACCEPTED, | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| async def handle_data(self, info: Info, data: Block): | ||||||||||||||||||||||||||||||||||||||||||
| # Handle one block of data | ||||||||||||||||||||||||||||||||||||||||||
| for event_with_tx in data.events: | ||||||||||||||||||||||||||||||||||||||||||
| tx_hash = felt.to_hex(event_with_tx.transaction.meta.hash) | ||||||||||||||||||||||||||||||||||||||||||
| event = event_with_tx.event | ||||||||||||||||||||||||||||||||||||||||||
| event_address = felt.to_hex(event.from_address) | ||||||||||||||||||||||||||||||||||||||||||
| logger.info("Transaction Hash:", tx_hash) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| if event_address != SPHERRE_CONTRACT_ADDRESS: | ||||||||||||||||||||||||||||||||||||||||||
| event_type = event.keys | ||||||||||||||||||||||||||||||||||||||||||
| event_enum = EVENT_SELECTORS.inverse[event_type] | ||||||||||||||||||||||||||||||||||||||||||
| transformed_data = DATA_TRANSFORMERS[event_enum](event) | ||||||||||||||||||||||||||||||||||||||||||
| if transformed_data: | ||||||||||||||||||||||||||||||||||||||||||
| DATA_HANDLERS[event_enum](transformed_data) | ||||||||||||||||||||||||||||||||||||||||||
| logger.info( | ||||||||||||||||||||||||||||||||||||||||||
| ( | ||||||||||||||||||||||||||||||||||||||||||
| f"Event with type '{event_type}' from address" | ||||||||||||||||||||||||||||||||||||||||||
| f"'{event_address}' handled" | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||
| logger.error( | ||||||||||||||||||||||||||||||||||||||||||
| ( | ||||||||||||||||||||||||||||||||||||||||||
| f"Failed to handle event of type '{event_type}'" | ||||||||||||||||||||||||||||||||||||||||||
| f"from address '{event_address}'" | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||
| event_type = event.keys | ||||||||||||||||||||||||||||||||||||||||||
| if event_type == EVENT_SELECTORS[EventEnum.ACCOUNT_CREATION]: | ||||||||||||||||||||||||||||||||||||||||||
| transformed_data = DATA_TRANSFORMERS[EventEnum.ACCOUNT_CREATION]( | ||||||||||||||||||||||||||||||||||||||||||
| event | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
| if transformed_data: | ||||||||||||||||||||||||||||||||||||||||||
| DATA_HANDLERS[EventEnum.ACCOUNT_CREATION](transformed_data) | ||||||||||||||||||||||||||||||||||||||||||
| self.start_account_indexer(transformed_data.account_address) | ||||||||||||||||||||||||||||||||||||||||||
| logger.info( | ||||||||||||||||||||||||||||||||||||||||||
| ( | ||||||||||||||||||||||||||||||||||||||||||
| "Account created for address " | ||||||||||||||||||||||||||||||||||||||||||
| f"'{transformed_data.account_address}'" | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||
| account_address = felt.to_hex(event.data[0]) | ||||||||||||||||||||||||||||||||||||||||||
| logger.error( | ||||||||||||||||||||||||||||||||||||||||||
| ( | ||||||||||||||||||||||||||||||||||||||||||
| "Failed to handle account creation event" | ||||||||||||||||||||||||||||||||||||||||||
| f"of address '{account_address}'" | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| async def handle_invalidate(self, _info: Info, _cursor: Cursor): | ||||||||||||||||||||||||||||||||||||||||||
| raise ValueError("data must be finalized") | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| def run_in_thread(self): | ||||||||||||||||||||||||||||||||||||||||||
| pass | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+101
to
+102
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Remove unused function. This function is not called anywhere and has no implementation. Either implement it if it's needed for the threading strategy mentioned in previous review comments, or remove it. -def run_in_thread(self):
- pass
-
-📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| async def run_indexer( | ||||||||||||||||||||||||||||||||||||||||||
| server_url=None, | ||||||||||||||||||||||||||||||||||||||||||
| mongo_url=None, | ||||||||||||||||||||||||||||||||||||||||||
| restart=None, | ||||||||||||||||||||||||||||||||||||||||||
| dna_token=None, | ||||||||||||||||||||||||||||||||||||||||||
| indexer_cls=None, | ||||||||||||||||||||||||||||||||||||||||||
| indexer_args=None, | ||||||||||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||||||||||
| runner = IndexerRunner( | ||||||||||||||||||||||||||||||||||||||||||
| config=IndexerRunnerConfiguration( | ||||||||||||||||||||||||||||||||||||||||||
| stream_url=server_url, | ||||||||||||||||||||||||||||||||||||||||||
| storage_url=mongo_url, | ||||||||||||||||||||||||||||||||||||||||||
| token=dna_token, | ||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||
| reset_state=restart, | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| await runner.run(indexer_cls(indexer_args), ctx={"network": NETWORK}) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| async def run_main_indexer( | ||||||||||||||||||||||||||||||||||||||||||
| server_url=None, mongo_url=None, restart=None, dna_token=None | ||||||||||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||||||||||
| runner = IndexerRunner( | ||||||||||||||||||||||||||||||||||||||||||
| config=IndexerRunnerConfiguration( | ||||||||||||||||||||||||||||||||||||||||||
| stream_url=server_url, | ||||||||||||||||||||||||||||||||||||||||||
| storage_url=mongo_url, | ||||||||||||||||||||||||||||||||||||||||||
| token=dna_token, | ||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||
| reset_state=restart, | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| await runner.run(SpherreMainIndexer(), ctx={"network": NETWORK}) | ||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| from enum import Enum | ||
| from typing import Any, List, get_args, get_origin | ||
|
|
||
| from apibara.starknet import felt | ||
| from bidict import bidict | ||
| from pydantic import BaseModel, ValidationInfo, field_validator | ||
|
|
||
|
|
||
| class EventEnum(Enum): | ||
| ACCOUNT_CREATION = 1 | ||
| TOKEN_TRANSFER = 2 | ||
| TRANSACTION_PROPOSAL = 3 | ||
| TRANSACTION_APPROVAL = 4 | ||
| TRANSACTION_EXECUTION = 5 | ||
|
|
||
|
|
||
| EVENT_SELECTORS = bidict( | ||
| { | ||
| EventEnum.ACCOUNT_CREATION: felt.from_hex( | ||
| "0x347f3a34b919109f055acc8440a003ecda76b4c63c101bbc99b9d00296db557" | ||
| ), | ||
| EventEnum.TOKEN_TRANSFER: felt.from_hex( | ||
| "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" | ||
| ), | ||
| EventEnum.TRANSACTION_PROPOSAL: felt.from_hex(""), | ||
| EventEnum.TRANSACTION_APPROVAL: felt.from_hex( | ||
| "0x8fac5268bfb16142e4e1fce5f985e337db83f8b307525a0960480cd8473436" | ||
| ), | ||
| EventEnum.TRANSACTION_EXECUTION: felt.from_hex( | ||
| "0x1dcde06aabdbca2f80aa51392b345d7549d7757aa855f7e37f5d335ac8243b1" | ||
| ), | ||
| } | ||
| ) | ||
|
Comment on lines
+17
to
+33
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Selector initialization currently raises immediately.
🤖 Prompt for AI Agents |
||
|
|
||
|
|
||
| class BaseEventModel(BaseModel): | ||
| def __init__(self, *args, **kwargs): | ||
| if args and not kwargs: | ||
| # If only positional args provided, map to fields | ||
| field_names = list(self.model_fields.keys()) | ||
| kwargs = dict(zip(field_names, args)) | ||
| super().__init__(**kwargs) | ||
|
|
||
| @field_validator("*", mode="before") # Apply to all fields | ||
| @classmethod | ||
| def restructure_data_before_parsing(cls, v: Any, info: ValidationInfo): | ||
| field_info = cls.model_fields[info.field_name] | ||
| field_type = field_info.annotation | ||
|
|
||
| print(f"\n{info.field_name}:") | ||
| print(f" Annotation: {field_type}") | ||
|
|
||
| new_value = v | ||
|
|
||
| if isinstance(field_type, str): | ||
| new_value = felt.to_hex(v) | ||
| return new_value | ||
| elif isinstance(field_type, int): | ||
| new_value = felt.to_int(v) | ||
| elif get_origin(field_type): | ||
| args = get_args(field_type) | ||
| if isinstance(args, str): | ||
| new_value = [felt.to_hex(val) for val in v] | ||
| elif isinstance(args, int): | ||
| new_value = [felt.to_int(val) for val in v] | ||
|
|
||
| return new_value | ||
|
Comment on lines
+44
to
+67
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Major: Fix type checking logic and remove debug prints. The validator has two issues:
Apply this diff to fix the type checks: @field_validator("*", mode="before")
@classmethod
def restructure_data_before_parsing(cls, v: Any, info: ValidationInfo):
field_info = cls.model_fields[info.field_name]
field_type = field_info.annotation
- print(f"\n{info.field_name}:")
- print(f" Annotation: {field_type}")
new_value = v
- if isinstance(field_type, str):
+ if field_type is str:
new_value = felt.to_hex(v)
return new_value
- elif isinstance(field_type, int):
+ elif field_type is int:
new_value = felt.to_int(v)
elif get_origin(field_type):
args = get_args(field_type)
- if isinstance(args, str):
+ if args and args[0] is str:
new_value = [felt.to_hex(val) for val in v]
- elif isinstance(args, int):
+ elif args and args[0] is int:
new_value = [felt.to_int(val) for val in v]
return new_value🤖 Prompt for AI Agents |
||
|
|
||
|
|
||
| class AccountCreationEvent(BaseEventModel): | ||
| account_address: str | ||
| owner: str | ||
| name: str | ||
| description: str | ||
| members: List[str] | ||
| threshold: int | ||
| deployer: int | ||
| date_deployed: int | ||
|
|
||
|
|
||
| class TokenTransferEvent(BaseEventModel): | ||
| account_address: str | ||
| from_address: str | ||
| to_address: str | ||
| amount: int | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,58 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from typing import Callable, Dict | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from apibara.starknet import felt | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from apibara.starknet.proto.starknet_pb2 import Event | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from loguru import logger | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from pydantic import ValidationError | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from spherre.indexer.service.types import ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| AccountCreationEvent, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| BaseEventModel, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| EventEnum, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class DataTransformer: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @classmethod | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def transform_account_creation_event(cls, event: Event) -> AccountCreationEvent: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| account_address = felt.to_hex(event.data[0]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| owner = felt.to_hex(event.data[1]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name = felt.to_hex(event.data[2]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| description = felt.to_hex(event.data[3]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| members_array_length = felt.to_int(event.data[4]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| members = [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for i in range(5, members_array_length + 1 + 4): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| members.append(felt.to_hex(event.data[i])) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| threshold = felt.to_int(event.data[i + 1]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| deployer = felt.to_int(event.data[i + 2]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| date_deployed = felt.to_int(event.data[i + 3]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+17
to
+28
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical: Fix array parsing logic and return type. The array parsing has critical errors:
Apply this diff to fix the logic: @classmethod
- def transform_account_creation_event(cls, event: Event) -> AccountCreationEvent:
+ def transform_account_creation_event(cls, event: Event) -> Optional[AccountCreationEvent]:
account_address = felt.to_hex(event.data[0])
owner = felt.to_hex(event.data[1])
name = felt.to_hex(event.data[2])
description = felt.to_hex(event.data[3])
members_array_length = felt.to_int(event.data[4])
members = []
- for i in range(5, members_array_length + 1 + 4):
+ cursor = 5
+ for _ in range(members_array_length):
- members.append(felt.to_hex(event.data[i]))
+ members.append(felt.to_hex(event.data[cursor]))
+ cursor += 1
- threshold = felt.to_int(event.data[i + 1])
- deployer = felt.to_int(event.data[i + 2])
- date_deployed = felt.to_int(event.data[i + 3])
+ threshold = felt.to_int(event.data[cursor])
+ deployer = felt.to_int(event.data[cursor + 1])
+ date_deployed = felt.to_int(event.data[cursor + 2])Add the import: -from typing import Callable, Dict
+from typing import Callable, Dict, Optional📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| print("Account Deployed") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| print("Account Address:", account_address) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| print("Owner:", owner) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| print("Name:", name) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| print("Description:", description) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| print("Members:", members) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| print("Threshold:", threshold) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| print("Deployer:", deployer) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| print("Date Deployed:", date_deployed) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| account_data = AccountCreationEvent( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| account_address=account_address, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| owner=owner, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name=name, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| description=description, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| members=members, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| threshold=threshold, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| deployer=deployer, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| date_deployed=date_deployed, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| except ValidationError as err: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.error("Error parsing account creation event data") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.error(err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return account_data | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DATA_TRANSFORMERS: Dict[EventEnum, Callable[[Event], BaseEventModel]] = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| EventEnum.ACCOUNT_CREATION: DataTransformer.transform_account_creation_event, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fail fast when required config is missing.
Leaving
SPHERRE_CONTRACT_ADDRESS,SERVER_URL, andMONGO_URLas empty strings makesfelt.from_hex("")crash at runtime and the runner attempt to dial an empty URL. Please plumb these values from env or config and raise a clear error if they aren’t provided before starting the indexer.