ERC-5646: Token State Fingerprint
ERC-5646 lets a token expose a deterministic hash of its mutable state — the state fingerprint. Indexers, marketplaces, collateral managers, and audit tools can use the fingerprint to detect state changes between snapshots without re-fetching every field. Critical for:
- NFT-collateral lending protocols — verify an NFT's state hasn't changed since collateralisation (e.g. in-game stats not drained).
- Marketplace listings — detect if an NFT has changed (metadata, unlock state, equipped items) since being listed.
- Indexer synchronisation — quick cache-invalidation check rather than diffing every field.
- Audit trails — store fingerprints at known block heights for later verification.
Required Interface
interface IERC5646 {
function getStateFingerprint(uint256 tokenId) external view returns (bytes32);
}The fingerprint computation is contract-specific; the convention is to hash all relevant mutable state (current owner, lock state, equipped items, dynamic metadata, etc.) into a single 32-byte digest.
Neo Equivalent: NEP-11 + Per-Token State Hash View
[Safe]
public static ByteString GetStateFingerprint(ByteString tokenId)
{
var components = new ByteString[] {
OwnerOf(tokenId),
IsLocked(tokenId) ? (ByteString)new byte[]{1} : (ByteString)new byte[]{0},
TransferCount(tokenId).ToByteArray(),
// ... any other mutable per-token state ...
};
var concat = (ByteString)new byte[0];
for (var i = 0; i < components.Length; i++)
concat = concat.Concat(components[i] ?? (ByteString)new byte[0]);
return CryptoLib.Sha256(concat);
}| ERC-5646 (Ethereum) | Neo Equivalent | Notes |
|---|---|---|
getStateFingerprint(tokenId) returns bytes32 | GetStateFingerprint(tokenId) returns ByteString (32 bytes) | Direct port |
keccak256 over canonical state | Sha256 over canonical state | Native curve choice |
| Field selection per implementation | Same — contract picks what's "relevant state" | Document the choice prominently |
What To Include In The Fingerprint
The standard intentionally leaves field selection to the implementation. Common patterns:
- Always include: tokenId, owner, lock state, soulbound flag, any custom mutable per-token storage.
- Include if present: equipped items (per ERC-6220), pinned metadata index (ERC-7160), active asset list (ERC-5773), parent pointer (ERC-6059), rental user (ERC-4907), entitled action list (ERC-5380), redemption status (ERC-2135 / ERC-6672).
- Don't include: contract-level state (totalSupply, name, symbol — those don't change per-token), non-state metadata (mint timestamp, immutable fields).
The implementation must document what's included so consumers can verify off-chain.
Composition
ERC-5646 is implementable on top of any NEP-11 with mutable per-token state. The fingerprint becomes more useful as more extensions contribute to the hash (locks, rentals, equipment, etc.).
Migration Notes
For NFT-collateral lending protocols porting:
- The lender records
GetStateFingerprint(tokenId)at collateralisation. - On default / liquidation, re-fetch the fingerprint — if it matches, the NFT's state is unchanged (no covert drain of value).
- If the fingerprint differs, the borrower extracted value during the loan (e.g. detached an equipped sword); slash collateral accordingly.
For indexers, snapshot fingerprints at fixed block intervals; only re-fetch full token state if the fingerprint has changed since the last snapshot.
