Skip to main content

NotaRegistry

The NotaRegistry contract (Solidity name NotareumNotaRegistry) is the on-chain source of truth for every .nota resource. It stores resource records, enforces unique resource IDs, maintains human-readable aliases, and records revocation state. Every other contract that reasons about resources (VerificationEngine, SlashingManager) consults this registry; every off-chain SDK consumer resolves resources through it.

Responsibilities

  • Map bytes32 resourceIdResource record.
  • Enforce uniqueness: one record per (resourceType, chainId, identifier) triple.
  • Maintain alias → resourceId mappings.
  • Authorize updates and revocation to the resource owner.
  • Emit the canonical events that indexers consume.
The registry stores no signatures or attestation content. The signed .nota payload lives off-chain; the registry only holds enough metadata to anchor trust decisions.

Resource record

The registry intentionally stores notaHash rather than the full payload. Consumers pair the on-chain record with the off-chain .nota file and verify the hash matches. This keeps gas costs bounded regardless of payload size.

Resource ID computation

This exact formula is replicated byte-for-byte in all three SDKs. The abi.encodePacked encoding is stable because uint8 and uint256 are fixed-width; bytes is appended without a length prefix (valid because it is the final argument).

Function surface

registerResource

Creates a new resource record. Reverts if:
  • A record already exists for (resourceType, chainId, identifier).
  • The alias is non-empty and already registered to a different resource.
  • The caller has not paid the registration fee (see FeeManager).
Emits ResourceRegistered(resourceId, owner, resourceType, chainId, notaHash) and, if aliased, AliasSet(resourceId, aliasHash).

updateResource

Replaces the notaHash (pointer to the canonical .nota payload) and optionally sets a new alias. Preserves registeredAt, bumps updatedAt. Only the current owner can call. Emits ResourceUpdated and AliasSet.

revokeResource

Marks a resource as revoked. Irreversible at the record level; revocation can only be reversed by registering a fresh resource (which computes a new ID only if the identifier changes). Reason string is emitted on-chain for indexers. Emits ResourceRevoked(resourceId, reason).

getResource

Returns the full record. For non-existent IDs, returns the zero record with owner == address(0); callers must check owner != 0 before trusting other fields.

resolveAlias

Returns the resource ID bound to the alias, or bytes32(0) if unbound.

ownerOf

Returns the current owner. Zero for non-existent resources. Ownership can be transferred via a dedicated transferOwnership(resourceId, newOwner) call (gated by the current owner).

Events

The aliasName string is emitted unindexed for display; the indexed aliasHash supports efficient lookups.

Access control

NotaRegistry integrates with AccessManager for two administrative surfaces: All resource-level writes (registerResource, updateResource, revokeResource) are permissionless, gated only by ownership of the target resource and payment of the applicable fee.

Alias semantics

Aliases are human-readable pointers (“acme.eth”, “vitalik”, “meridian-collection”). The registry hashes the alias to bytes32 for storage, and stores a reverse aliasHash → resourceId mapping. Rules:
  1. First-come-first-served allocation.
  2. Case-folded and NFC-normalized at the contract boundary before hashing.
  3. An alias can be released (and reclaimed by others) only by the resource owner.
  4. Revoked resources release their alias automatically.
ENS interoperability is intentional but not required. You can register bob.eth as a Notareum alias, or use a Notareum-native alias (bob.nota) with no ENS registration.

Gas notes

  • registerResource is dominated by two SSTOREs (the record and the alias entry). Without alias, expect ≈180k gas; with alias, ≈240k.
  • updateResource reuses the existing slots: ≈75k gas without alias change, ≈110k with alias change.
  • revokeResource touches a single boolean and emits an event: ≈50k gas.
  • getResource is a view and free for off-chain callers.
The identifier field is bytes, which costs one storage slot per 32 bytes plus a length slot. Typical EVM addresses (20 bytes) fit in one slot; long identifiers (IPFS CIDs, Cosmos bech32 strings) can span two slots.

SDK usage

Indexer-friendly queries

Subgraph entities derived from events:
The subgraph deployment in contracts/subgraph/notareum is the reference implementation consumed by the dApp and SDK explorer helpers.

Invariants

  1. For every resource, resourceId == keccak256(abi.encodePacked(type, chainId, identifier)).
  2. At most one resource per (type, chainId, identifier) triple; subsequent writes replace-only after revocation.
  3. Every alias maps to at most one non-revoked resource; revoked resources release alias on the next registration touching it.
  4. registeredAt is immutable once set.