Deployments
The canonical, shared ABX infrastructure — the clone factories (trust anchors) and the stateless singletons every project reuses, deployed as public goods.
The machine-readable source of truth is packages/sdk/src/deployments.ts (keyed by EIP-155 chainId). This page mirrors it for humans — if the two ever disagree, the manifest wins, and the drift is a bug. The toolkit resolves every address by override → env → manifest: a --factory/--renderer/… flag, then the matching ABX_* env var, then the manifest below.
Same address on every chain
Every contract below except the generator is deployed through the keyless CREATE2 proxy
(, present on every EVM chain) with a canonical salt
(contracts/script/AbxSalts.sol).
Identical salt + identical initcode ⇒ the same address on every chain — so the whole infra set is
one address list, and a new chain deploys to the same addresses (computable before the first
transaction). The factory implementations are cross-chain-identical too: a factory does exactly one
CREATE at nonce 1 from its own (identical) address.
Production (mainnet)
None yet. ABX is in a testnet-only alpha — the supported chain targets today are sepolia and
base-sepolia (see SDK → Chains). Mainnet and L2 production entries are intentionally
absent until the canonical set is deployed and funded on those chains (Distribution roadmap). When they
are, these addresses are the same there too.
Canonical infrastructure (Sepolia · Base Sepolia — identical)
| Contract | Env override | Address (all chains) |
|---|---|---|
OneOfOneImageFactory (1/1 anchor) | ABX_FACTORY | |
SeriesImageFactory (Series anchor) | ABX_SERIES_FACTORY | |
SeriesCodeFactory (code anchor) | ABX_SERIES_CODE_FACTORY | |
OneOfOneEditionFactory (1/1-edition anchor) | ABX_ONE_OF_ONE_EDITION_FACTORY | |
EditionImageFactory (edition anchor) | ABX_EDITION_FACTORY | |
EditionCodeFactory (code-edition anchor) | ABX_EDITION_CODE_FACTORY | |
AbxMetadataRenderer (spec v11) | ABX_RENDERER | |
AbxChunkStore (SSTORE2 reader) | ABX_CHUNK_STORE | |
AbxSeedSource (mint-time pseudorandom seed) | ABX_SEED_SOURCE | |
AbxFixedPriceMinter (shared 721 sale) | ABX_FIXED_PRICE_MINTER | |
AbxFixedPriceMinter1155 (per-id edition sale) | ABX_FIXED_PRICE_MINTER_1155 | |
AbxMetadataLib (delegatecalled write path) | — | |
AbxParamsLib (delegatecalled write path) | — | |
AbxCodeLib (delegatecalled write path) | — | |
AbxEditionLib (delegatecalled write path) | — |
Factory EIP-1167 implementations (also identical on every chain): OneOfOneImage
· SeriesImage
· SeriesCode
· OneOfOneEdition
· EditionImage
· EditionCode
.
One deployment, re-cut 2026-08-20
Every address on this page comes from one source tree, and nothing here descends from an earlier generation. That is deliberate: ABX is pre-launch, so rather than layering a migration on top of the previous set, the whole thing is re-cut whenever the contracts change — greenfield, so old anchors are simply forgotten.
The 2026-08-20 batch added opt-in burn and an owner-set, reduce-only royalty cap (up to 100%),
on top of moving the Params/ConfigurableParams write shells into AbxParamsLib (the extraction that
bought the two code tokens their EIP-170 headroom back). So it moved all six token factories and
their implementations, plus AbxParamsLib and AbxEditionLib (which links it). What did not
move — because their initcode is unchanged — is checkable rather than asserted: the renderer (spec
v11), the generator, the chunk store, the seed source, both minters, and AbxMetadataLib /
AbxCodeLib keep their addresses. A CREATE2 address is a function of the initcode, so what moved is
something you can verify.
Two consequences worth stating plainly:
- Projects deployed from any earlier anchor are not covered by this page. They keep working on
their frozen implementations, but they are not canonical against this manifest, and
abxwill report their factory as an older version. Redeploy from the anchors above. creatorandcreator_linksreplacedartistandartist_linksas on-chain collection metadata field keys, andAuthOption.ArtistbecameAuthOption.Creator. Renderer spec version moved to 7 for exactly this reason — a v6 renderer emits a different member key, so it is genuinely behind rather than cosmetically so.- Renderer spec version is now 8. v8 removed the
abx_paramsblock from the token document and narrowed each field's provenance note to the route the value took rather than a claim about where it ends up. A renderer that still emitsabx_paramsdescribes params the contract no longer guarantees it can enumerate the same way, so v7 is genuinely behind too. Params remain readable on-chain from the token itself — see Params. - The on-chain metadata field store moved into
AbxMetadataLib, a delegatecalled library all six token types link. That is what bought the two code types their EIP-170 headroom, and it is why every implementation address on this page moved even where the token's own behavior did not.
The factory address is the trust anchor: a contract is canonical when the chain's factory
deployed it (verified via isAbxClone, not the spoofable AbxDeployed beacon — see
Authenticity). The rest are stateless, ownerless singletons
referenced by address.
Anchor generations — "canonically ABX v2"
The six factories above are one generation, identified by the core spec version its clones report
as abxVersion() — currently v2. A generation is what a redeploy batch replaces, and the SDK
records them in ANCHOR_GENERATIONS so a consumer can distinguish two answers that would otherwise
both be a bare false:
- deployed by an ABX factory that has since been replaced — canonically ABX, older;
- deployed outside the toolkit entirely.
verifyProvenance() returns which, plus the core version, so the sayable answer is "canonically ABX
v2" rather than a boolean. It is checkable without trusting this page: the version is on the clone
itself, which is also why the answer survives its factory being retired.
Two rules this list lives by. It is provenance, never trust — a retired generation never widens
verifyCanonical, because a superseded generation can predate a security remediation, and the gate
must stay exactly as narrow as the current anchors. And one core version, one generation — every
token-layer redeploy bumps AbxVersion.CORE_VERSION, enforced by a test rather than a convention.
Pre-launch generations are deliberately not enumerated: they were testnet-only and disposable, so a collection deployed by one reads as not-canonical until it is redeployed or re-registered. Git has their addresses; the manifest records what is live and, from the first batch that retires an anchor set, what it replaced.
Per-chain (the generator)
AbxGenerator (ABX_GENERATOR) — the animation_url field renderer for code projects — bakes
chain-specific immutables (per-chain runtime-asset pointers and the dependency registry), so its
address differs per chain:
| Chain | AbxGenerator |
|---|---|
Sepolia (11155111) | |
Base Sepolia (84532) |
Linked libraries and external pointers
All six token types delegatecall part of themselves into separately deployed libraries — every one
of them the on-chain metadata field store, and the code and edition types their write paths on top of
that. Linking one costs nothing in determinism: the libraries are CREATE2-deployed
through the same keyless proxy at their own canonical salts, and linking is a substitution of an
address into already-compiled bytecode, so the linked factory's initcode — and therefore its
address — is fixed as soon as the libraries' are. (A deployer's nonce is an input to plain CREATE,
never to a CREATE2 address. The recorded library addresses have always been chain-identical, and one
of them landed at the same address on both chains from deployer nonces 215 apart.) The salts:
| Library | Salt string (AbxSalts.sol) | keccak256(salt) |
|---|---|---|
AbxMetadataLib | abx.lib.metadata.v1 | 0xd7580b1da51d3bf89d2b793e13ac1555022c9b180961c117e86b9ab1a84680b9 |
AbxParamsLib | abx.lib.params.v1 | 0xbf0c74210ab6a4720d238a4ce2636e2c2ce21a378a8f7688db175e0fd05697d5 |
AbxCodeLib | abx.lib.code.v1 | 0x04c93005461fa51fa65cb9fbcf3d4ef591b3f9d1e7f01c6ddac70116149002bd |
AbxEditionLib | abx.lib.edition.v1 | 0x84bb4cc42185d7007eb139933b5ef32e59c09e94267ed5e0a4a6b3ad71c14d4a |
AbxEditionLib delegatecalls AbxParamsLib, so it is itself linked before it is deployed — the one
library whose initcode depends on another library's address.
The four libraries are listed in the main table above, deployed explicitly by
DeployLibraries.s.sol at the salts named here — not by forge's automatic linking, which routes
through the same proxy but at its own salt of zero. Which library each token links:
| Token type | Links |
|---|---|
SeriesCode | AbxMetadataLib, AbxParamsLib, AbxCodeLib |
EditionCode | AbxMetadataLib, AbxParamsLib, AbxCodeLib, AbxEditionLib |
OneOfOneEdition, EditionImage | AbxMetadataLib, AbxEditionLib |
OneOfOneImage, SeriesImage | AbxMetadataLib |
AbxMetadataLib is the one every type links: the on-chain metadata field store — the setField /
lockField write paths and the reads over them — lives there rather than in each token. Externalizing
it is what put the two code types back under EIP-170 with room to spare, and it means the two ERC-721
image types, which linked nothing before, link one library now.
Do not pass --libraries when deploying. Compile-time linking writes the address map into
settings.libraries, which is part of the metadata JSON whose hash is appended to the bytecode —
so it changes the initcode, and therefore the CREATE2 address, of the very contracts it is meant to
pin. Measured: adding it moves all five library-linked addresses. The deploy scripts substitute the
placeholder in the compiled artifact instead (script/AbxLink.sol),
which is also the only method the SDK can use — it ships bytecode, it does not compile — and that
is what keeps the two lanes on one address.
- Art Blocks
DependencyRegistryV0(ABX_DEPENDENCY_REGISTRY) — thename@versionresolution root ABX reads but never deploys: Sepolia ; Base Sepolia has none (collections point at their own, or the resolver's built-in CDN map).
Verifying an address
Every contract on this page is source-verified on both chains — open any address in the explorer (Etherscan for Sepolia, Basescan for Base Sepolia) and you can read the exact Solidity it runs, rather than taking our word for it. The trust anchors are meant to be audited, so a canonical address that shows up unverified is a bug worth reporting.
Any address here is also checkable on-chain — the renderer, for example, reports its spec:
cast call <renderer> "specVersion()(uint256)" --rpc-url <rpc> # → 11Adding or updating a chain
Standing up a new chain runs the same script/Deploy*.s.sol with the same salts → the same
addresses as above (the canonical set), so you can publish them before the first transaction.
Deploying a fresh singleton (or a new contract revision) is an owner op that ends in a manifest edit.
See the contract-change checklist,
the authoritative workflow (redeploy → verify → update deployments.ts and this page).
The write-path libraries go first
CREATE2 for libraries is the standard process, not an accident of the toolchain. Deploy them explicitly, before anything that links them:
# print the three canonical library addresses — sends nothing
forge script script/DeployLibraries.s.sol --sig 'predict()'
# then deploy them (idempotent: a library that already has code is reported and skipped)
forge script script/DeployLibraries.s.sol --rpc-url <rpc> --broadcastThe addresses predict() prints are the ones the SDK predicts (predictParamsLib(),
predictCodeLib(), predictEditionLib() in create2.ts), so a chain bootstrapped with forge and a
chain bootstrapped by the toolkit agree. The SDK's own lazy bootstrap (deploySeriesCodeFactory /
deployEditionCodeFactory, used for sandboxes and private chains) does the same thing in the same
order — CREATE2 at the same salts, skipping any library already on-chain — so a partially set-up
chain is finished, never duplicated.
A library's address is a function of its creation bytecode, so build settings move it. Two ways to get this silently wrong:
- Compile-time linking. Passing
--libraries src/…:Lib:0x…toforge build/forge scriptwrites that map intosettings.librariesin every artifact's metadata, and the metadata hash is appended to the creation bytecode — so the library's own address moves, and so does the linked factory's. Linking after compilation (substituting into solc's__$…$__placeholder, which is what forge's automatic linking, the deploy scripts (script/AbxLink.sol), and the SDK all do) cannot have that effect. - Optimizer profile. The code tokens compile at
optimizer_runs = 200while everything else runs at 1,000,000, and a library inherits the profile of the unit that pulls it in. The canonical library bytecode is the default-profile artifact — the onevm.getCodereturns andpnpm sync-abisships to the SDK.
Both failures are invisible until two chains disagree, so check rather than assume: each
script's --sig 'predict()' and the SDK's matching predict*() must print the same address — all
five of them (three libraries, two code factories). If they differ, the build settings differ, or
generated.ts is stale (pnpm sync-abis).