TZ2AT system design and FAQ.
TZ2AT turns Tezos chain activity, selected OBJKT marketplace context, and user-requested hydration into AT Protocol records. The system is built around one hard rule: live head indexing comes first, and every slower process must run beside it rather than in front of it.
Downstream products are appviews, feed generators, wallet experiences, analytics tools, and social graph services. They consume TZ2AT by reading category PDS repos, subscribing to a firehose, or asking the relay for targeted projections.
System Map
1. Sources
2. Independent Converters
3. Storage And Publication
4. Downstream Products
Design invariant: if a route can lag, it must lag independently. OBJKT, TzKT hydration, entity provisioning, S3 archive, and PDS publication can be behind without making the rolling indexer stop following head.
Event Grammar
TZ2AT treats chain and marketplace records as statements made from nouns, verbs, and parameters. The verb is the action: sale, offer, transfer, curation add, listing, bid, wallet claim, and related event types. The nouns are the identity-centered things involved: wallets, contracts, tokens, marketplaces, currencies, platforms, and chains. Parameters are the values that make the statement precise: price, amount, token ID, block level, operation hash, timestamp, source, and provenance.
This is the source of the noun repo convention. TZ2AT makes nouns durable by giving them categorized repos or stable repo-local records. It stores verbs as event records inside the repos they describe. That means repo placement is itself semantic context, not just an implementation detail.
A flat event stream can tell you that something happened. The PDS tree tells you which durable things the event belongs to, so an appview can reconstruct the map: wallet to token, token to contract, contract to marketplace, marketplace to currency, and all of it back to Tezos provenance.
Data Routes
| Route | Purpose | Output | Must not do |
|---|---|---|---|
Octez -> rolling converter -> hot store | Follow current Tezos head. | Canonical block, transaction, FA2, XTZ, origination, and raw observation records. | Wait for OBJKT, TzKT, PDS publishing, or appview queries. |
OBJKT tank -> pairer -> artifacts | Use OBJKT as a second ingestion route for market and token context. | Paired marketplace events, token definitions, metadata, market state, project/curation/referral artifacts. | Replace chain facts or overload hot ingestion with unrestricted broad streams. |
TzKT -> hydrator -> converters | Backfill wallets and repair gaps. | Historic events and artifacts processed through the same storage/firehose route as live data. | Run in the critical path of head indexing. |
Entity queue -> provisioner -> category PDS | Create missing noun repos and publish waiting artifacts. | Wallet, contract, marketplace, currency, platform, and chain repos. | Drop artifacts because the repo did not exist yet. |
Historian -> lifecycle records | Keep permanent boundary facts without replaying all history into every repo. | genesis, last-seen, and OBJKT profile anchors. | Turn into unrequested full-history backfill. |
PDS Tree
TZ2AT publishes records into repos organized by what the repo is about. Appviews should usually start from the repo for the noun they are displaying, then follow references and graph edges outward. The repo category is part of the semantic statement: wallet repos hold wallet-centered facts, contract repos hold contract and token facts, and marketplace repos hold market action context.
| PDS host | Repo category | Use it for |
|---|---|---|
wallets.tz2at.store | Wallet repos | Wallet profiles, lifecycle anchors, wallet-link identity artifacts, wallet-token edges, wallet-contract edges, and relevant wallet event copies. |
contracts.tz2at.store | Contract repos | Contract profiles, contract lifecycle anchors, token definitions, token metadata, contract-token edges, and contract-level event context. |
marketplaces.tz2at.store | Marketplace repos | Marketplace profiles, collect/swap/bid context, token-market edges, and market projections. |
platforms.tz2at.store | Platform repos | OBJKT, Tezos, Etherlink, jstz, project, curation, referral, and platform-level context. |
currencies.tz2at.store | Currency repos | Currency profiles and market payment asset context. |
chains.tz2at.store | Chain repos | Network profiles, block anchors, and chain-level provenance. |
tz2at.store | Root relay repo | Canonical relay records and the store.tz2at.* publication surface. |
How To Build An Appview
wallets.tz2at.store; token questions usually start in the contract repo.Minimal repo read
const host = "https://contracts.tz2at.store";
const repo = "did:plc:example";
const collection = "store.tz2at.token.definition";
const url = host + "/xrpc/com.atproto.repo.listRecords"
+ "?repo=" + encodeURIComponent(repo)
+ "&collection=" + encodeURIComponent(collection)
+ "&limit=100";
const records = await fetch(url).then((r) => r.json());
Wallet hydration flow
await fetch("https://tz2at.xyz/hydrate/wallet/async", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
did: "did:plc:youruser",
walletAddress: "tz1...",
maxPages: 20
})
});
Firehose Use
Use the JSON firehose for simple web consumers and the ATProto sync firehose when you want native repo operations.
| Surface | Endpoint | Best for |
|---|---|---|
| JSON firehose | wss://tz2at.xyz/firehose | Fast appview prototypes, dashboards, and consumers that want normalized event envelopes. |
| ATProto sync | wss://relay.tz2at.store/xrpc/com.atproto.sync.subscribeRepos | Indexers that already understand ATProto repo commits and CAR blocks. |
| Replay | https://tz2at.xyz/replay?fromLevel=N&toLevel=M | Recovering missed blocks or bootstrapping a local appview index. |
const ws = new WebSocket("wss://tz2at.xyz/firehose");
ws.onmessage = (message) => {
const envelope = JSON.parse(message.data);
if (envelope.event?.$type === "store.tz2at.fa2.transfer") {
// update your local token movement projection
}
};
Common Records
Canonical events
store.tz2at.blockstore.tz2at.transactionstore.tz2at.originationstore.tz2at.xtz.flowstore.tz2at.fa2.transferstore.tz2at.fa12.transferstore.tz2at.marketplace.collectstore.tz2at.marketplace.swapstore.tz2at.marketplace.bid
Semantic records
store.tz2at.wallet.lifecyclestore.tz2at.contract.lifecyclestore.tz2at.wallet.objktProfilestore.tz2at.contract.objktProfilestore.tz2at.token.definitionstore.tz2at.token.metadatastore.tz2at.objkt.groupstore.tz2at.edge.walletTokenstore.tz2at.projection.tokenMarketState
Records include provenance fields so appviews can trace whether a fact came from Octez, TzKT hydration, OBJKT, the lifecycle historian, or a user identity proof route.
Retention And Reliability
TZ2AT has three practical storage temperatures:
- Hot: Postgres and live PDS repos for fresh query and firehose use.
- Warm: S3 block/event archives for replay after hot eviction.
- Cold: deeper archive for data that should be kept but rarely queried.
Permanent entity anchors, such as wallet genesis, wallet last-seen, contract genesis, contract last-seen, and OBJKT profile anchors, are designed to survive ordinary hot retention. High-volume event copies can be evicted from hot storage once they are archived and no longer needed for fresh appview queries.
FAQ
What is TZ2AT?
TZ2AT is a Tezos-to-AT Protocol relay. It indexes Tezos and selected marketplace context, converts useful facts into ATProto records, and publishes them into repos that appviews can consume.
Is TZ2AT a wallet?
No. TZ2AT can help a user associate a Tezos wallet with an AT Protocol DID, but it does not custody funds or sign Tezos operations.
What does it mean to link a wallet?
A user proves control of a Tezos wallet and TZ2AT writes wallet-link records under the relevant repo surfaces. Users can also choose whether matching event copies stay only in TZ2AT, are copied to their personal PDS, or both.
Why use AT Protocol for Tezos data?
ATProto gives Tezos data portable repos, handles, firehose subscriptions, and appview-friendly records. That makes chain data easier to combine with identity, social feeds, curation, games, and community tools.
What is the most important system rule?
The rolling indexer must stay at head. Any process that can fall behind, such as OBJKT enrichment, hydration, provisioning, or archive movement, must run separately.
What happens if the indexer misses blocks?
The live indexer should skip back to head and a detached repair worker should backfill the missing range. Current head remains priority one.
Does TZ2AT index all OBJKT data?
No. OBJKT is a second ingestion route, but TZ2AT is selective. It focuses on token identity, market context, projects, curations, ACTZ exhibitions, referral records, and data that helps interpret chain records.
Why not hot-ingest every OBJKT stream?
Broad streams can create enormous bycatch and rate-limit pressure. TZ2AT prefers hot streams that produce high-value graph context, then uses scoped hydration when an appview or user needs more.
What is a noun repo?
A noun repo is an ATProto repo for a durable thing in a Tezos statement: wallet, contract, marketplace, currency, platform, or chain. We call them nouns because blockchain event records behave like sentences. The event type is the verb, the involved identities and objects are nouns, and fields such as price, token ID, block, and operation hash are parameters.
TZ2AT stores verbs as event records in the repos for the nouns they describe. That structure helps appviews recreate the semantic graph instead of treating every event as an isolated row.
Where do token records live?
Tokens live under their contract repo on contracts.tz2at.store. A token is not usually its own repo; it is a record and graph node inside the minting contract's repo.
How does an appview get live updates?
Use wss://tz2at.xyz/firehose for JSON envelopes or wss://relay.tz2at.store/xrpc/com.atproto.sync.subscribeRepos for native ATProto repo commits.
How does an appview get historic wallet data?
Call POST /hydrate/wallet/async for the wallet. The background worker pulls TzKT history and feeds it into the same converter/storage path as live data.
Can I build a feed from TZ2AT?
Yes. Subscribe to the firehose, filter for records such as marketplace events, referrals, curation groups, or wallet-linked activity, then publish your own feed logic as an appview.
Can I build a wallet-history app?
Yes. Let the user connect with an AT Protocol identity, prove wallet ownership, choose where portable copies should live, request hydration, then query wallet repo records and wallet activity projections.
Can I build a token page?
Yes. Start with /api/semantic/tokens/:network/:contract/:tokenId, then read the contract repo for token definition, metadata, market state, owner state, and graph edges.
What should appviews store locally?
Store your firehose cursor, the records you derive into product state, and enough source references to replay or explain your derivation later.
What is provenance?
Provenance tells you where a record came from: Octez live RPC, OBJKT, TzKT hydration, lifecycle historian, identity proof, or another route. Appviews should preserve it when making claims.
Are wallet inventory projections final truth?
They are convenient projections. If a wallet was not fully hydrated, a rolling-window projection can be incomplete. Appviews that need complete balances should request hydration or use an ownership-state source.
How are records evicted?
High-volume hot records can move to warm S3 and later cold storage. Permanent lifecycle and OBJKT profile anchors are designed to remain in entity repos.
How do I find repos?
Use GET /api/semantic/nouns or GET /api/semantic/entity-accounts to list noun handles, DIDs, categories, and PDS hosts.
FAQ version: current live architecture as of 2026-05-28. See the builder manual for the full record catalog and API list, or the user guide for the wallet claim flow.