Skip to Content
ProtocolMemo Format

Memo Format

Overview

Every ZNS memo is a UTF-8 string stored verbatim in the 512-byte Orchard memo field of a Zcash shielded note. Trailing NUL bytes are trimmed during parsing. Each memo begins with the literal prefix ZNS: followed by an action keyword.

The colon byte : (0x3A) is the only delimiter. It is forbidden inside any field value - names, addresses, nonces, prices, signatures all exclude it. The parser uses a small number of splitn calls on :, so getting the arity wrong results in a rejected memo.

Memo Format

ActionMemo format
ClaimZNS:CLAIM:<name>:<ua>:<sig>
UpdateZNS:UPDATE:<name>:<new_ua>:<nonce>:<sig>
ListZNS:LIST:<name>:<price>:<nonce>:<sig>
DelistZNS:DELIST:<name>:<nonce>:<sig>
BuyZNS:BUY:<name>:<buyer_ua>:<sig>
ReleaseZNS:RELEASE:<name>:<nonce>:<sig>
Set priceZNS:SETPRICE:<count>:<p1>:…:<pN>:<nonce>:<sig>

Field conventions:

  • <name> - 1–62 characters of lowercase ASCII letters and digits only. See Name Validation.
  • <ua>, <new_ua>, <buyer_ua> - a bech32m zcash unified-address string.
  • <nonce>, <price>, <p1>…<pN>, <count> - a plain decimal ASCII integer.
  • <sig> - 64-byte Ed25519 signature encoded as base64, not base64url (88 characters with padding).

The signature is always the last colon-separated field. See Signature Scheme for the pre-image templates and the verification procedure.


CLAIM

ZNS:CLAIM:<name>:<ua>:<sig>

Register a new name. Admission rules:

  • name passes validation.
  • name is not already in registrations.
  • Signature over CLAIM:{name}:{ua} verifies against admin_pubkey.
  • Note value ≥ current claim cost for name.length (from the pricing table).
  • Pricing has been initialized with a SETPRICE memo observed on chain

Example:

ZNS:CLAIM:alice:utest1f32kn6c4zvn54xr8wfsnxmj9hzpu2mwgtxzpzwcw3490…:AQIDBAUG…

On success: the name is registered.


UPDATE

ZNS:UPDATE:<name>:<new_ua>:<nonce>:<sig>

Update the address a name resolves to.

  • name exists.
  • Signature over UPDATE:{name}:{new_ua}:{nonce} verifies.
  • nonce > current_nonce.

On success: ua, txid, height, nonce, signature, and last_action = "UPDATE" are updated.


LIST

ZNS:LIST:<name>:<price>:<nonce>:<sig>

Create or replace a marketplace listing. <price> is in zatoshis.

  • name exists.
  • Signature over LIST:{name}:{price}:{nonce} verifies.
  • nonce > current_nonce.

On success: the listings row is inserted or replaced with the new price, nonce, and signature. The registrations row is not touched - last_action stays whatever it was.


DELIST

ZNS:DELIST:<name>:<nonce>:<sig>

Remove the marketplace listing for a name.

  • name exists.
  • Signature over DELIST:{name}:{nonce} verifies.
  • nonce > current_nonce.

On success: the listings row is deleted. The registrations row’s signature and last_action = "DELIST" are updated.


BUY

ZNS:BUY:<name>:<buyer_ua>:<sig>

Purchase a listed name. BUY does not use a nonce - the listing itself is proof of intent.

  • Name is currently listed.
  • Signature over BUY:{name}:{buyer_ua} verifies.
  • Note value ≥ listings.price.

On success (atomic): registrations.ua becomes buyer_ua, nonce resets to 0, signature and last_action = "BUY" are updated, and the listings row is deleted.


RELEASE

ZNS:RELEASE:<name>:<nonce>:<sig>

Permanently delete a registration. The name returns to the Available state.

  • name exists.
  • Signature over RELEASE:{name}:{nonce} verifies.
  • nonce > current_nonce.

On success: both the registrations row and any listings row for the name are deleted. No history is retained beyond the events table.


SETPRICE

ZNS:SETPRICE:<count>:<p1>:<p2>:…:<pN>:<nonce>:<sig>

Update the claim-pricing table.*

  • count = number of tier values that follow. Required; disambiguates the end of the tier list from the nonce and signature even when tiers include zeros.
  • p1 through pN are decimal integers in multiples of 10,000 zats, indexed by name length (p1 for 1-char names, etc.). The last value is the catchall for names of that length and longer. 0 = free.
  • nonce > current_pricing_nonce.
  • Signature over SETPRICE:{count}:{p1}:…:{pN}:{nonce} verifies against admin_pubkey.

SETPRICE does not require a payment - it’s typically a 0.0001 ZEC self-send that only exists to carry the memo.

*Admin-only action. Only the protocol admin can update pricing. Pricing initializes when the first SETPRICE memo is confirmed on-chain.

See Pricing for activation semantics and the bootstrap requirement.


Size budget

The Orchard memo field is 512 bytes. Every ZNS memo must fit inside it. In practice the longest are CLAIM and UPDATE, because they embed a unified address (usually ~140–270 bytes) in addition to the signature (~88 bytes base64) and the static prefix.

A conservative rule of thumb: if your UA is shorter than 380 bytes, you have room for any action.

Invalid memos

The indexer silently ignores memos that:

  • Don’t start with ZNS:.
  • Match a known prefix but have the wrong arity.
  • Fail signature verification.
  • Contain an invalid UA, name, or numeric field.
  • Arrive with a stale nonce.

Invalid memos still settle as normal Zcash transactions. There is no refund and no error signal - the memo is simply not indexed. Clients should pre-validate before asking a user to sign a transaction.

Last updated on