Name identity
Every layer uses the same deterministic identity relationship.
normalizedName -> UTF-8 bytes -> keccak256 -> nameId -> uint256 -> tokenIdTypeScript example
import { keccak256, stringToBytes } from 'viem'
export function computeNameId(normalizedName: string) {
return keccak256(stringToBytes(normalizedName))
}
export function computeTokenId(normalizedName: string) {
return BigInt(computeNameId(normalizedName))
}Call the canonical normalization function before hashing. The example intentionally does not implement normalization because copying a partial policy creates collision risk.
Solidity invariant
The mint controller and registry both verify:
keccak256(bytes(normalizedName)) == nameIdThe registry then uses uint256(nameId) as the token ID. There is no incrementing token counter and no reverse mapping required to reconstruct this relationship.
Fixtures
The repository includes shared fixed-name fixtures. TypeScript and Foundry tests independently check their calculated values against the same constants to detect cross-language drift.