auradefi 0.1.1
PyPI GitHub

Auradefi

auradefi.embed.facade · source

The library's public surface (SPEC §8).

source must structurally satisfy BOTH portfolio.holdings.BalanceSource (balances, for holdings) and embed.sync.PageFetcher (fetch_txlist, for history): one object, two seams, so a host writes one adapter.

__init__

__init__(self, ledger: LedgerPort, source: BalanceSource | PageFetcher, prices: PriceOracle, clock: Clock | None = None, settings: Settings | None = None, *, sync_state: SyncStatePort | None = None, decoder: Decoder | None = None, sync_page_size: int = 1000) -> None

Bind the host's ports. ZERO I/O happens here.

clock=None means SystemClock(), settings=None means Settings(), sync_state=None means MemorySyncState() (in-process; a host that wants durable cursors binds its own). A pre-seeded ChainRegistry, per instance, it is mutable, is built here and gates connect_address.

decoder=None binds the default composition LAZILY, at first use, sources.evm.txlist.parse_normal_row per row -> decode.pipeline.decode_account -> ledger.bridge, so importing this module stays cheap and dependency-light.

Raises auradefi.errors.ValidationError when source does not satisfy both seams: the failure belongs at bind time, not at the first background tick.

Parameters

ledgerrequired, LedgerPort

Where transactions are stored. Four methods, tenant-scoped.

sourcerequired, BalanceSource | PageFetcher

Your chain data. Must satisfy BOTH seams: balances and fetch_txlist: or binding raises immediately.

pricesrequired, PriceOracle

Your price feed. Returning nothing for an asset is allowed and means unpriced, never zero.

clockoptional, Clock | None, default None

None means SystemClock(). Time is a port so quota windows and throttling are testable.

settingsoptional, Settings | None, default None

None means Settings(). Carries the sync interval and the project id that tenant ids derive under.

sync_stateoptional, SyncStatePort | None, default None

Connections and cursors. None means in-process, which forgets every connection on restart.

decoderoptional, Decoder | None, default None

Row-format seam. None binds the EVM txlist decoder lazily.

sync_page_sizeoptional, int, default 1000

How many rows to ask a source for per page.

Raises

ValidationError

sandbox

sandbox(cls, *, connect: bool = True, **overrides: object) -> Auradefi

A working instance over a bundled recording, no keys, no network.

Production code paths, RECORDED data: answers are constants (5025 USD, seven transactions) and anything unrecorded raises CassetteMissError. The address arrives connected unless connect=False; ports override by keyword. See sandbox_ports.

Parameters

connectoptional, bool, default True

Whether to return with the sandbox address already connected. False to call connect_address yourself.

overridesoptional, object

Any port, by keyword, replacing that default.

Raises

CassetteMissError

from_env

from_env(cls, **overrides: object) -> Auradefi

A live instance wired from the environment (SPEC §8).

Reads AURADEFI_ETHERSCAN_API_KEY (optional) and AURADEFI_HTTP_TIMEOUT_S. Storage is in-memory and NOT durable: pass ledger=SqlModelLedger(...) to keep data, since the host owns the engine and the migrations. See env_ports.

Parameters

overridesoptional, object

Any port, by keyword. ledger= is the one most hosts set, since the default is not durable.

user

user(self, external_user_id: str) -> UserHandle

Get-or-create the handle for one opaque host user id.

Pure: no I/O and no persistence. The tenant id is DERIVED from the id (embed.models.derive_tenant_id) under settings.project_id, so the same string always resolves to the same tenant, and to the SAME one that project's HTTP API resolves it to (RELEASE_0.1.1 §5 #19). Raises auradefi.errors.ValidationError for anything outside the pinned opaque-id charset (an email is guessable and this is bearer-equivalent, so @ cannot appear).

Parameters

external_user_idrequired, str

Your opaque id for the person. The tenant id is derived from it; @ is refused because this is bearer-equivalent.

Raises

ValidationError

sync

sync(self, budget: int = 5) -> SyncReport

One tick across every known connection, in creation order.

ONE shared budget of page requests is spent connection by connection until it runs out; connections beyond that point are not visited this tick. budget < 1 raises auradefi.errors.ValidationError. The aggregate sums the per-connection counts, and no_op is True exactly when every VISITED connection was a no-op: vacuously True with zero connections. Self-throttling comes from settings.sync_min_interval_s.

Parameters

budgetoptional, int, default 5

Maximum source pages this ONE call may spend across every connection. Cursors make the next call resume.

Raises

ValidationError

holdings

holdings(self) -> tuple[HoldingsReport, ...]

One priced HoldingsReport per connection, creation order.

scalar_metrics

scalar_metrics(self) -> tuple[scalar_projection.Metric, ...]

(name, ms, float) triples per connection, concatenated.

Each connection contributes project.scalar.scalar_metrics over its own holdings report and its own transactions: the non-removed ADDED-kind ledger rows whose account_id is that connection's id, read by paging ledger.sync until has_more is False.