abx.
Protocol

Event spine & ERC standards

The event spine is the set of events an ABX contract emits. With the read interfaces, it forms the ABX protocol. Concrete contracts emit these events, and services such as indexers, resolvers, and render nodes read them to track a project's state.

The spine has two registers: the standard ERC events, and a native ABX layer.

Structure

  • One project per contract. A project is identified by its contract address. There is no projectId.
  • A required core with opt-in extensions. The core is an ERC-165-discoverable ERC-721 or ERC-1155 contract that emits one required event, AbxDeployed. All other events belong to opt-in extensions. A Series is many unique tokens (ERC-721); an Edition is many copies of a token (ERC-1155).
  • An open set. New extensions can be defined. The ones documented here are the current canonical set.

Two registers

Every state change is announced in both registers.

RegisterRead byPurpose
Standard ERC and OpenSea eventsexisting indexers and marketplacescompatibility with tools that have no ABX awareness
Native ABX eventsABX-aware resolvers and render nodesre-indexing a project's state from the logs

Where a standard already defines a signal, ABX emits it verbatim alongside the native event.

Register 1: the standards ABX speaks

These are emitted with their canonical signatures, so existing indexers read ABX contracts without special-casing.

  • ERC-721: ownership (Transfer, Approval, ApprovalForAll). A mint is a transfer from 0x0, so no ABX-specific mint event is needed.
  • ERC-1155: ownership and metadata-refresh for the edition contracts (OneOfOneEdition, EditionImage, EditionCode) — TransferSingle, TransferBatch, URI, and the same ApprovalForAll. A mint is a transfer from 0x0, same as ERC-721.
  • ERC-2309 (optional): a batch mint as a single event.
  • ERC-4906: MetadataUpdate and BatchMetadataUpdate, the metadata-update signal marketplaces read — emitted and ERC-165-advertised on both lanes. The standard is nominally a 721 extension, but the range form is what the ecosystem actually consumes for ERC-1155 too, and this repo's IERC4906 is event-only, so 0x49064906 is a refresh marker rather than a claim of ERC-721 support. An edition emits ERC-1155's native URI in addition, but not everywhere a 4906 ping fires: URI has no range variant, so a contract-wide re-point signals only via 4906 plus its own config event, and a per-id override write skips URI when an on-chain renderer is configured (the event would have to carry the whole rendered document). pingURI(ids) is the owner-only, caller-chunked helper for re-emitting per-id refresh events afterward: it emits MetadataUpdate(id) for every id named, plus native URI(uri(id), id) when no on-chain renderer is configured. It is owner-only because that matches what it is for — an owner's follow-up to their own re-point — and because with an on-chain renderer a permissionless version is asymmetric: the caller pays event gas while an event-driven indexer may perform an expensive uri(id) per id, for arbitrary, duplicate, or nonexistent ids.
  • ERC-7572: ContractURIUpdated, for contract-level metadata.
  • ERC-2981: royalty resolution, via the royaltyInfo view.
  • ERC-721-C (or its ERC-1155 twin, ERC-1155C, on an edition — opt-in per deploy): royalty enforcement, for creators who want it. A collection that enrolls at deploy emits TransferValidatorUpdated at enrollment and on every validator change, and advertises the creator-token interfaces via ERC-165 — only when enrolled; an unenrolled collection carries no trace of the standard. See Royalty enforcement.
  • ERC-7496, ERC-5192, OpenSea PermanentURI (optional): on-chain traits, soulbound tokens, and frozen metadata.

The current ABX contracts implement a subset of these standards. The others are listed because the protocol is designed to speak them, and future implementations may add them as needed.

Register 2: the native ABX layer

These are opt-in extensions, advertised through ERC-165. Each defines its events and, where it has a read surface, its interface.

  • AbxDeployed: the one required event, emitted once at deploy. It is an open discovery signal: a resolver finds ABX contracts by watching this event, and any implementation may emit it, including custom ones. It signals discovery, not authenticity. See Authenticity.
  • Royalty, Primary Payee, External Minter, Max Invocations, Paused: sale and ownership configuration.
  • Edition Supply: the ERC-1155 analogue of Max Invocations, scoped per id instead of per project — each id's max supply, only ever decreasing. The one extension new to editions; every other extension id is shared, unchanged, between the two standards.
  • Creator Token: the opt-in ERC-721C surface as an ABX extension — ERC-1155C on an edition, same extension id, same ERC-165 ids, same enrollment rule. Its beacon version is reported only when the token enrolled at deploy; the standard's own TransferValidatorUpdated event carries the state, so the extension adds no native events.
  • On-Chain Script, Dependencies, Seed Source: code as content. A chunked on-chain program, its ordered libraries, and a mint-time pseudorandom seed stored as configuration.
  • On-Chain Metadata, Params, Configurable Params: the field-and-representation store and typed parameters. See Metadata and Parameters. Authorship and rights (creator, display_notes, creator_links, license) are reserved keys in this store, not a separate extension.

Re-indexing from the logs

A contract's AbxDeployed event, its per-extension version events, and its ERC-165 responses tell a resolver which contracts are ABX, which events to follow, at which version, and which addresses to watch. A project's configuration is expressed by which extensions it enables. A resolver, such as the self-hosted reference implementation, re-indexes a project's state from these events and reads its content bytes from content-addressed data.

Resolving an edition id's cap

An ERC-1155 edition's copy limit comes from two events, and reading only the per-id one is the mistake worth naming, because it is wrong in the common case:

  • DefaultMaxSupplySet(cap) — emitted once at deploy. The collection-wide default for every id (--copies N; 0 means open). Most projects stop here: setMaxSupply is never called, so no id has a per-id event of its own.
  • MaxSupplyUpdated(id, cap) — that id overriding the default, only ever downward. Its presence also means the id is explicitly overridden.

An id's effective cap is its own override if it has one, otherwise the collection default. That matches the maxSupply(id) read exactly. What the read cannot tell you is what a 0 means: an id never capped is open, an id deliberately overridden to 0 is closed forever, and both return 0. The log distinguishes them — an override event exists only for the second — which is why anything rendering a buy button should fold the log rather than trust the getter alone.

The SDK does this for you: ProjectState.defaultMaxSupply, each token's effective maxSupply and maxSupplyOverridden, and editionCapOf(token) returning open / capped / closed.

Authenticity

AbxDeployed finds contracts; it does not vouch for them. Because any contract can emit it, discovery and trust are separate steps. The source of truth is the canonical factory for each chain: a contract is a canonical ABX contract when that factory deployed it, which a consumer verifies against the factory. The SDK reports this as isCanonical, and the canonical addresses per chain are in the SDK deployments.

The protocol is the spine and the interfaces, not one implementation. The canonical factory marks the reference implementation ABX publishes, but anyone can build a conforming implementation and emit AbxDeployed.

Versioning

Versioning is per-extension, through AbxExtensionVersionSet and extensionVersion(id). No event carries a version field, and older projects remain readable when new versions are added. Standard events are pinned to their canonical signatures.

Interfaces, Metadata, Code projects, Data plane, Effects

On this page