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
| Action | Memo format |
|---|---|
| Claim | ZNS:CLAIM:<name>:<ua>:<sig> |
| Update | ZNS:UPDATE:<name>:<new_ua>:<nonce>:<sig> |
| List | ZNS:LIST:<name>:<price>:<nonce>:<sig> |
| Delist | ZNS:DELIST:<name>:<nonce>:<sig> |
| Buy | ZNS:BUY:<name>:<buyer_ua>:<sig> |
| Release | ZNS:RELEASE:<name>:<nonce>:<sig> |
| Set price | ZNS: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:
namepasses validation.nameis not already inregistrations.- Signature over
CLAIM:{name}:{ua}verifies againstadmin_pubkey. - Note value ≥ current claim cost for
name.length(from the pricing table). - Pricing has been initialized with a
SETPRICEmemo 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.
nameexists.- 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.
nameexists.- 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.
nameexists.- 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.
nameexists.- 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.p1throughpNare decimal integers in multiples of 10,000 zats, indexed by name length (p1for 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 againstadmin_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.