WritingDisabled
Written1 / 2000
Permanent0 / 2000
Block25,641,944snapshotJul 30 00:01 UTC

How it works

identity.md is a collection of 2,000 tokens on Ethereum. The artwork is not a stored image file: the contract generates the SVG each time it is asked for it. Each token can carry an identity — a document hash stored on chain that points at content on IPFS, and that the artwork prints in its footer.

This site reads all of it directly from the contracts and renders it: every token, every attribute, and any written identity. It holds no wallet, requests no signature, and makes no state-changing call.

Collection figures on this site were read at block 25,641,944 (2026-07-30 00:01:11 UTC).

Can I write an identity to my token?

As of block 25,641,947 (2026-07-30 00:01:47 UTC), writing is not enabled on either contract: setIdentityHash(uint256,string,bool) reverts IdentityHashNotAllowed() on both the NFT and the registry. The registry currently holds a hash for 1 of 2,000 tokens. The state page lists the raw reads and the registry's event history.

contractfunctionresult
NFT
setIdentityHash(uint256,string,bool)
(1, "probe", true)
reverts IdentityHashNotAllowed()
Registry
setIdentityHash(uint256,string,bool)
(1, "probe", true)
reverts IdentityHashNotAllowed()
NFT
setIdentityAllowed(bool)
(true)
reverts Unauthorized()
Registry
setIdentityAllowed(bool)
(true)
reverts Unauthorized()
NFT
mint(uint256)
(1)
reverts AlreadyMinted()
NFT
setApprovalForAll(address,bool)
(caller, true)
call succeeds

Each row is one eth_call simulation from an address with no relationship to the collection. mint takes the id as an argument, so one simulation describes one id: ids 01999 revert AlreadyMinted(), and 2,000 and above revert TokenIdOutOfRange(). The remaining recovered entry points are standard ERC-721 approval, transfer and ownership functions.

Full write surface: every recovered entry point, the simulation method, and the mint probes

State-changing entry points were recovered from each contract's bytecode (see Method below), then simulated with eth_call. Every result is what one caller sees at block 25,641,947 (2026-07-30 00:01:47 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(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.

Two identity stores

The NFT and the registry each keep their own identity hash per token — two separate stores on two separate contracts. tokenURI reads the NFT's store, which is empty for every token, while the registry holds a hash for 1 of 2,000. That is why every token's canonical render carries Memory State = Unwritten even though 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.

The functions behind the two stores

Each contract exposes its own identityHash(uint256) and identityAllowed(). These are separate storage on separate contracts; neither is a proxy for the other. 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. The registry also exposes identityURI(uint256), which returns the stored hash in ipfs:// form, and hasIdentityHash(uint256).

Three reachable render states

The renderer takes identity state as arguments rather than reading it from storage: tokenURI(uint256,string,bool,bool) accepts a hash and two bools, and is a view function callable by anyone. All four bool combinations were called for the same token id and the returned bytes compared. Three distinct states come back:

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

The fourth combination, (written=false, permanent=true), returns bytes identical to (false, false): the second bool has no effect unless the first is set.

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.

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's recovered read functions

The renderer is deployed separately from the NFT. Three read functions were recovered from its bytecode (see Method below):

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 are view functions callable by anyone, which is what makes the state previews on this site possible.

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.

Method: recovered from bytecode, then called

No published ABI was used. Function selectors were recovered from each contract's deployed bytecode by scanning for PUSH4 immediates and matching them against a generated space of candidate signatures — and a match is only believed after calling it, because a PUSH4 constant proves a byte sequence exists in the code, not that it is a function selector. This is the recovery step referenced throughout this page.

Every figure on this site comes from a script in the repository that writes a JSON file the pages read. 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.