WritingDisabled
Written1 / 2000
Permanent0 / 2000
Block25,634,495

How it works

This site is an independent viewer for the identity.md collection. It renders every token from data read off Ethereum mainnet: the art and attributes are decoded from tokenURI, and identity state is read from the registry contract. It holds no wallet, requests no signature, and makes no state-changing call.

Collection figures on this site were read at block 25,634,495 (2026-07-28 23:06:23 UTC).

Contracts

NFT0x0000eC93127BAA929E58E97dd0095A2BFb38ec1D
Holds the tokens. tokenURI reads from here.
Registry0x000008061ccac597a321a75e3470a3e8faf9dd2d
A second identity store, with its own identityHash per token.
Renderer0x3F559eF271B245E7e754fEAD7d50cd55aC981423
Produces the metadata and the SVG. Read functions are public.

The renderer address is not hardcoded on this site. It is resolved by calling renderer() on the NFT, so the address above is whichever renderer the NFT pointed at when the data was read.

The renderer is a separate contract

The renderer is deployed separately from the NFT and exposes public read functions that anyone can call. Three were recovered from its bytecode by scanning for PUSH4 selector immediates, then confirmed by calling each one:

0x44b285db
svg(uint256)
Returns the SVG for a token id.
0x0488d096
svg(uint256,string,bool,bool)
Returns the SVG with identity state supplied as arguments.
0x8d0c0a06
tokenURI(uint256,string,bool,bool)
Returns the full metadata data URI with identity state supplied as arguments.

The two four-argument forms take identity state as arguments instead of reading it from storage. They are view functions callable by anyone, which is what makes the state previews on this site possible.

Two identity stores

The NFT and the registry each expose identityHash(uint256) and identityAllowed(). These are separate storage on separate contracts; neither is a proxy for the other.

tokenURI on the NFT reads the NFT's own store. Reading both stores across all 2,000 tokens returns an empty string from the NFT for every id, and a hash from the registry for 1 of them. That is why every token's canonical render carries Memory State = Unwritten while the registry holds a hash for token 0.

Memory State and Memory Lock are attributes the renderer emits from the arguments it is given. They are not reads of registry storage.

Three reachable render states

The two bool arguments to tokenURI(uint256,string,bool,bool) give four combinations. All four were called for the same token id and the returned bytes compared. (written=false, permanent=true) is byte-identical to (false, false): the second bool has no effect unless the first is set. Three distinct states are reachable, not four.

argumentsMemory StateMemory LockattributesSVG footer
false, falseUnwrittenOpen7IPFS / UNWRITTEN
false, trueUnwrittenOpen7IPFS / UNWRITTEN
true, falseWrittenMutable8IPFS / <hash>
true, trueWrittenPermanent8IPFS LOCKED / <hash>

Between the unwritten and written states, one <text> element in the SVG changes and two attribute values change. The written states add an eighth Identity Hash attribute and an external_url field. All markup outside the <text> elements is byte-identical, so the geometry does not depend on identity state.

The hash argument is printed into the SVG footer exactly as passed. Calling with a bare CID and calling with the same CID prefixed ipfs:// produce different bytes. The registry stores the bare form in identityHash; identityURI returns the prefixed form.

What is callable now

State-changing entry points were recovered from each contract's bytecode by the same PUSH4 selector scan, then simulated with eth_call. Every result below is what one caller sees at block 25,636,506 (2026-07-29 05:50:11 UTC), with the arguments shown.

caller = 0x1111111111111111111111111111111111111111 — an address with no relationship to the collection.

eth_call runs against a state snapshot and is discarded. Nothing here was broadcast, and a result describes that one call with those arguments at that block.

NFT

functionresult
approve(address,uint256)
0x095ea7b3
(caller, 1)
reverts NotOwnerNorApproved()
transferFrom(address,address,uint256)
0x23b872dd
(caller, caller, 1)
reverts TransferFromIncorrectOwner()
safeTransferFrom(address,address,uint256)
0x42842e0e
(caller, caller, 1)
reverts TransferFromIncorrectOwner()
renounceOwnership()
0x715018a6
()
reverts Unauthorized()
mint(uint256)
0xa0712d68
(1)
reverts AlreadyMinted()
setApprovalForAll(address,bool)
0xa22cb465
(caller, true)
call succeeds
setIdentityHash(uint256,string,bool)
0xa89db6c2
(1, "probe", true)
reverts IdentityHashNotAllowed()
safeTransferFrom(address,address,uint256,bytes)
0xb88d4fde
(caller, caller, 1, 0x)
reverts TransferFromIncorrectOwner()
transferOwnership(address)
0xf2fde38b
(caller)
reverts Unauthorized()
setIdentityAllowed(bool)
0xfd50578e
(true)
reverts Unauthorized()

registry

functionresult
renounceOwnership()
0x715018a6
()
reverts Unauthorized()
setIdentityHash(uint256,string,bool)
0xa89db6c2
(1, "probe", true)
reverts IdentityHashNotAllowed()
transferOwnership(address)
0xf2fde38b
(caller)
reverts Unauthorized()
setIdentityAllowed(bool)
0xfd50578e
(true)
reverts Unauthorized()

renderer

No state-changing entry point matched the candidate signature space. 53 PUSH4 constants in this contract's code were not resolved to a name, so this is the result of a search, not an enumeration of the contract.

mint(uint256) across the id range

mint takes the id as an argument, so one simulation only describes one id.

mint(0)reverts AlreadyMinted()
mint(1)reverts AlreadyMinted()
mint(1,999)reverts AlreadyMinted()
mint(2,000)reverts TokenIdOutOfRange()
mint(5,000)reverts TokenIdOutOfRange()

Revert names are resolved by search, not assumption: a revert returns four bytes of a keccak preimage, which is matched against a generated space of candidate error signatures. A selector no candidate hits is reported as unresolved rather than named.

How the state previews are made

Every token page has an Unwritten / Written / Permanent toggle. Each position shows real output from the renderer: 4,000 SVGs were fetched by calling tokenURI(uint256,string,bool,bool) once per token per state and saved to disk at build time. None is produced by editing an existing file.

The arguments are only sourced from chain for token 0, whose hash comes from registry.identityHash(0) and whose permanence flag comes from the third parameter of that token's IdentityHashUpdated log. For every other id the registry holds no hash, so a sample string is passed instead and the result is labelled HYPOTHETICAL on the tab, in an amber dashed frame around the art, and in the caption below it.

Preview data is read only by the token page. It does not reach the grid, the filters or any count on this site. The Written and Permanent figures in the status bar come from registry.hasIdentityHash and the IdentityHashUpdated logs.

Reproducing any of this

Every figure on this site comes from a script in the repository that writes a JSON file the pages read. Contract ABIs were recovered from deployed bytecode rather than a published source, and each recovered selector is called before it is believed. Chain access is eth_call, eth_getLogs and eth_getCode only.

The state page lists the raw contract reads and the registry's event history. The archetype page compares the two places an archetype name appears.

Affiliation

This is an independent reader. It is not affiliated with the identity.md collection or its creators, and it is not a source of authority on the collection. The contracts linked above are.