Quickstart
Five lines, no credentials.
pip install auradefi
from auradefi import Auradefi aura = Auradefi.sandbox() for holding in aura.holdings()[0].holdings: print(holding.symbol, holding.quantity, holding.value)
ETH 2 5000.000000000000000000 USD USDC 25 25.000000 USD
That is a complete program. It needs no API key, no database, no network and no configuration file.
What just happened
Auradefi.sandbox() opens the Sandbox environment: a recording of one
address' real Etherscan and DefiLlama traffic, bundled inside the package and
replayed locally. Everything above the transport is the production code path,
using the same source, decoder, ledger and pricing arithmetic as a live
instance.
Sandbox exists so you can write working code before anyone has approved an API key. It also keeps the examples in these docs from drifting away from the library.
| Address | 0x1111111111111111111111111111111111111111 on eip155:1 |
| Holdings | 2 ETH at 2500 USD and 25 USDC at 1 USD, totalling 5025 USD |
| History | seven transactions in blocks 100 to 107 |
| Time | frozen at the instant the traffic was recorded |
Because Sandbox is a recording, its answers are constants. Ask for something
it does not hold, such as a different address, a second chain or a wider page,
and you get CassetteMissError listing what it does hold. That is the offline
guarantee working as intended.
Record your own Sandbox
One address is enough to learn the shape and not enough to test against your
own data. Recorder is the other half: point it at the live service once, and
every run after that is offline.
from auradefi.testing.cassettes import Recorder, load from auradefi.sources.evm.source import EtherscanSource with Recorder("mywallet.json") as recorder: # records EtherscanSource(recorder.client(), api_key=KEY).balances("eip155:1", ADDRESS) source = EtherscanSource(load("mywallet.json").client()) # replays, no key
The saved file is keyless on purpose. Query parameters that carry credentials are stripped as it writes, which is also what lets the replay run without a key at all. Response bodies are saved whole, so read a recording before you commit it: a service that echoes your credential back to you defeats the stripping.
Committed alongside your tests, that file gives you the offline guarantee this package holds itself to, over your addresses instead of ours.
Sync some history
report = aura.sync(budget=10) print(report.pages_fetched, report.transactions_ingested) # 5 7
budget caps how many source pages one call may spend. Cursors let the next
call resume where this one stopped, so a tick is bounded and keeps its place.
Call it again inside sync_min_interval_s and it is a no-op that touches no
transport:
aura.sync(budget=10).no_op # True
That is the whole scheduling contract. You call sync() on your own schedule,
from your own worker. The package starts no background thread, and nothing
runs unless you ask for it.
Go live
One line changes:
aura = Auradefi.from_env() user = aura.user("your-opaque-user-id") user.connect_address("eip155:1", "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045") aura.sync(budget=5)
export AURADEFI_ETHERSCAN_API_KEY=… # optional; see Authentication
The key is optional. Without one, Etherscan's keyless tier applies. Authentication & keys lists every service this package talks to, which of them need a credential (almost none do), and what each one covers.
Storage still defaults to memory at this point, so from_env() on its own
loses everything when the process exits. Passing your own database is one
keyword:
aura = Auradefi.from_env(ledger=SqlModelLedger(session_factory=…))
Bring your own has that in full, along with the other four ports.
Or serve it over HTTP
The library is the product and the HTTP API is one adapter over it, so the same ports you just bound also make an app:
from auradefi.api.app import create_app from auradefi.api.deps import Deps app = create_app(Deps(ledger=…, tenancy=…, keys=…, clock=…, …))
It holds no state, opens no connections and creates no stores. Responses use Plaid's wire format, so a client that already reads Plaid reads this. The journey a caller makes:
POST /auth/token server key -> short-lived user token POST /connections user token -> conn_… GET /crypto/sync user token -> added/modified/removed + cursor GET /coverage public -> the capability matrix, as data
Deps has more fields than the four above, and every one of them is a port
you already own. Guide 05 is a single
file that wires all of them and drives the result, and the
HTTP API page lists every route with its fields.
Where to go next
- Guides: one file per task, covering holdings, your own source, your own database, the HTTP API, tenancy, positions, cost basis, webhooks, Bitcoin and Solana.
- Authentication & keys: what you need before pointing this at mainnet, and what happens when a key is wrong.
- Limits and cost: what one call costs in requests, what the services allow, and what you get when you cross a line.
- Bring your own: every port, its exact methods, and a minimal implementation of each.
- Glossary: CAIP-2, parts, acts, tenants, cursors, and every other term these pages assume.
- API reference: signatures, parameters, return fields and exceptions.
- Build with an LLM: a prompt to paste into a model before
asking it for auradefi code, plus
llms.txtand the whole documentation as one file.
What this is not
auradefi is alpha, and the README keeps an explicit list of what is absent: one price oracle covering six EVM chains, no Bitcoin or Solana prices at all, no scheduler, and an EVM node path whose vectors were written by hand and never recorded from a chain. Read that list before you budget work against this. Sandbox makes the library easy to try, and the gaps are still there afterwards.