You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Posting this as a draft for comment. It is deliberately narrow, and it is meant to sit alongsidesRFC 00020, not compete with it — 00020 owns permissioning, clawback, halts, and distributions, and none of that is in scope here.
What this adds. When classification came up in the 00020 thread, the resolution was that issuers should self-declare their asset type and implement matching logic. That works for an issuer's own product surface and breaks down for anyone consuming tokens they did not issue: a self-declared string with no attestation is trivially spoofed, and minting a lookalike with matching metadata costs a few cents. This proposal adds a small shared vocabulary and a binding from that vocabulary to someone accountable — nothing more.
What is already verifiable, because a spec with no implementation is a blog post with a table in it:
The §3.1 schema encoding is pinned against sas-lib@1.0.10 and round-trips on devnet. Credential 5Es4gSTWYemJxPMkWGYAi56Xzf2cSosJBRMaQaVVuxZq, schema ASE1gwae1gBPZctkdNXdyGJcmqwPMVW9iMHqs22bJa9p, example attestation G6qArVxuNwL9aC3EpTY443TfVTfyFmKwQhgmnd6rht9b.
A dependency-free reference reader with 60 tests, including a layout round-trip through the real SDK rather than a reimplementation: https://github.com/pzupan/rwa-classification
No new program. This uses SAS as deployed.
Three findings from building it that may be useful regardless of what happens to this proposal:
SAS has no pubkey type code and no fixed-size byte array, so any schema carrying keys or hashes has to choose Vec<u8> or String and say which.
Fixing the attestation PDA nonce to the subject mint makes attestations discoverable by derivation — no indexer, no pointer, and it works for legacy SPL mints that cannot carry metadata.
There is no revoke instruction. closeAttestation deletes the account, so to anyone reading accounts a revoked attestation is byte-identical to one that never existed. Short expiry, not revocation, has to be the real control.
What I am asking for. Co-sponsorship before this advances past draft — specifically from the Foundation RWA group, Metaplex, and at least one competing issuer. I issue tokens in this category, and a classification standard authored solely by an issuer invites the reading that it is a distribution land grab. That is also why §3.7 refuses to name trusted attesters and why the adoption bar in §8 is set where it is.
Open questions I would most like comment on: whether rwa.claim should be multi-valued for hybrid instruments (§9.2), who maintains the subclass and namespace registries long-term (§9.3), and whether rwa.jurisdiction needs to be a list for cross-border SPV structures (§9.5).
A minimal, jurisdiction-agnostic convention for declaring what real-world asset a token represents, what claim the holder has on it, and where to find the extended data — bound to an expiring on-chain attestation so the declaration is verifiable rather than merely asserted.
This proposal deliberately does not specify transfer compliance mechanics. That is sRFC 00020's subject, and this is designed to sit alongside it.
Motivation
There is today no way for a wallet, indexer, or aggregator to determine that a Solana mint represents real estate — or any other asset class — without per-issuer bespoke integration.
sRFC 00020 covers permissioning, clawback, trading halts, and distributions. When classification came up in that thread, the resolution was that issuers should self-declare their asset type and implement matching logic. That is workable for an issuer's own product surface and unworkable for anyone consuming tokens they did not issue, because a self-declared string with no attestation is trivially spoofed. Any wallet that renders it as authoritative becomes a phishing surface: minting a token named RVBND with matching metadata costs a few cents.
Consumers currently fall back to name/symbol heuristics (unsafe), curated allowlists (unscalable, and each wallet maintains its own), or third-party aggregators (editorial, high-latency, poor small-issuer coverage).
The missing pieces are narrow: a small shared vocabulary, and a binding from that vocabulary to someone accountable.
Non-goals
Scope discipline is the main lesson from 00020's stall. Explicitly out of scope:
Transfer compliance and permissioning. See sRFC 00020.
NAV, valuation, and price oracles. The discussion in 00020 foundered here. This spec names where a NAV feed lives; it does not specify its integrity, cadence, or dispute resolution.
Exhaustive property schemas. Real estate has hundreds of relevant fields. None belong on-chain. They live behind discovery (§4).
Legal effect. Nothing here asserts that a token conveys title. A classification is a description, not a conveyance.
Identity/KYC of holders. SAS already covers this.
1. Layer overview
Layer
Location
Mutable by
Trust
1. Classification
Token-2022 additionalMetadata on the mint
Metadata update authority
Self-declared
2. Attestation
Solana Attestation Service
Attester (expiring; §3.4)
Verified
3. Discovery
Off-chain, signed + hash-pinned
Issuer
Mixed, see §4
Layer 1 alone is a convenience. Layer 1 without Layer 2 MUST NOT be presented as verified (§5). Layer 2 works standalone, which is how legacy SPL Token mints that cannot carry additionalMetadata participate.
2. Layer 1 — classification fields
Keys are namespaced rwa.* to avoid collision with existing conventions.
Key
Req.
Value
rwa.v
REQUIRED
Spec version. 1 for this document.
rwa.class
REQUIRED
Closed enum, §2.1
rwa.claim
REQUIRED
Closed enum, §2.2
rwa.jurisdiction
RECOMMENDED
ISO 3166-1 alpha-2, or 3166-2 where subdivision is material (US-TX)
rwa.issuer_lei
RECOMMENDED
ISO 17442 LEI of the issuing entity or SPV
rwa.attestation
OPTIONAL
Hint only; the address is derivable without it (§3.3)
rwa.subclass
OPTIONAL
Open registry, §2.3
rwa.api
OPTIONAL
HTTPS URL of the discovery document (§4)
Three required keys. Consumers MUST ignore unrecognized rwa.* keys rather than rejecting the token, so the vocabulary can grow without breaking readers.
2.1 rwa.class — what the asset is
Closed set. An open set is unfilterable and therefore useless for the routing and grouping decisions consumers need to make.
real-estate treasury corporate-credit private-credit
public-equity private-equity commodity fund
carbon receivable other
Anything unlisted uses other plus a rwa.subclass. Additions to this set require a spec version bump.
2.2 rwa.claim — what the holder owns
Closed set. This axis is orthogonal to rwa.class and omitting it is the most common failure in naive taxonomies.
A first-lien mortgage note secured by an apartment building and an equity stake in that same building are both real-estate, with inverted risk profiles, opposite behaviour in a downturn, and different regulatory treatment. A consumer that buckets them together on the strength of rwa.class alone actively misleads its users. Both fields are required so this cannot be skipped.
direct-title is reserved for tokens where the token itself is the instrument of title under some jurisdiction's law. It is expected to be rare and SHOULD carry an attestation naming the recording authority.
2.3 rwa.subclass — open registry
Extensible, maintained as a flat list in the reference repository, additions by PR without a version bump. For real-estate, the initial vocabulary aligns with the NCREIF/NAREIT core property types rather than inventing one:
Property identifiers are not carried in Layer 1. They are jurisdictional (US county APN, UK UPRN, FR cadastre) and they are a privacy hazard: a public parcel ID joined against public token balances and public property records deanonymizes a holder's position and, by extension, their net worth.
Where a property reference is needed it appears in the attestation (§3) as a commitment:
with namespace drawn from a registry of the form us-tx-travis-apn, gb-uprn, fr-cadastre. The preimage is disclosed off-chain to parties with standing — regulators, auditors, holders under NDA — not to chain observers.
3. Layer 2 — attestation
Layer 2 uses the Solana Attestation Service (program 22zoJMtdu4tQc2PzL74ZUT7FrwgB1Udec8DdW4yw4BdG, Apache-2.0, maintained by the Solana Foundation). No new program is required or proposed. Field encodings below are pinned against sas-lib@1.0.10 and verified end-to-end on devnet (§3.6).
A Credential identifies the attesting authority — a transfer agent, auditor, regulated registry, or exchange. A Schema named rwa.classification.v1 defines the claim. An Attestation binds a mint to a classification.
3.1 Schema layout
A SAS Schema account stores fieldNames alongside a layout byte array, one compact type code per field. The codes are the SDK's, not this spec's; the relevant subset is 12 = String and 13 = Vec<u8>. Attestation data is Borsh-encoded against the struct those two arrays describe.
rwa.classification.v1 is exactly:
#
Field
Code
Borsh type
Contents
0
mint
13
Vec<u8>
32 raw bytes. Subject of the claim (§5.1)
1
class
12
String
MUST match §2.1
2
claim
12
String
MUST match §2.2
3
subclass
12
String
MAY be empty
4
jurisdiction
12
String
ISO 3166
5
issuer_lei
12
String
ISO 17442, MAY be empty
6
property_commit
13
Vec<u8>
§2.4. 32 bytes, or empty if unused
7
discovery_url
12
String
Canonical §4 pointer
8
discovery_signer
13
Vec<u8>
32 raw bytes. Signs the §4 document
Field order is normative — Borsh is positional, and layout carries no names of its own beyond the parallel fieldNames array.
Pubkeys are 32 raw bytes, not base58 strings. SAS has no pubkey type code, so a key has to be carried as either Vec<u8> or String. This spec picks raw bytes: it is canonical, it is half the size, and it removes base58 as a place where two implementations can disagree. Consumers comparing against a base58 address MUST encode the attested bytes rather than decoding the address, so that a malformed value fails the comparison instead of throwing.
Vec<u8> is length-prefixed. A 32-byte value occupies 36 bytes on the wire. property_commit is the one field that MAY be empty rather than zero-filled; prefer empty, since 32 zero bytes is a valid-looking commitment to nothing.
A fully populated attestation serializes to 228 bytes.
3.2 Expiry is the account's, not the schema's
expires_at is deliberately absent from the schema. The SAS Attestation account already carries a native expiry field, set through the createAttestation instruction. Carrying a second copy inside the Borsh payload would create two sources of truth that can disagree, with no rule for which wins — and the native one is the only one the program itself can enforce. Consumers MUST read expiry from the account.
Expiry is mandatory. Appraisals go stale, SPVs dissolve, transfer agents get replaced, registrations lapse. An attestation without expiry is a claim about the past presented as a claim about the present.
3.3 Discovery without an indexer
The Attestation PDA derives from (credential, schema, nonce), where nonce is free-form. This spec fixes nonce = the subject mint.
That one choice makes attestations discoverable by derivation rather than search. A consumer holding a trust set already knows each attester's credential, and the schema PDA follows from it, so for any mint it can compute the exact attestation address and fetch it — one derivation and one account read per trusted attester, with no indexer, no log scanning, and no dependence on rwa.attestation being present or honest.
It follows that rwa.attestation (§2) is a convenience hint, never the authority: it is written by the same update authority as the rest of Layer 1. A consumer MUST NOT trust an attestation solely because Layer 1 pointed at it.
This also resolves how legacy SPL Token mints participate. They cannot carry additionalMetadata, but they need no pointer — the derivation is over the mint address, which every token has.
3.4 Revocation is deletion, and that has consequences
SAS has no revokeAttestation instruction. Revocation is closeAttestation, which deletes the account and emits a CloseAttestationEvent carrying the data that was destroyed.
This is worth stating plainly because it defeats the obvious reading of §5.4: to a consumer reading accounts, a revoked attestation and one that never existed are byte-for-byte identical. Only a party consuming program logs can tell them apart, and logs age out of most RPC providers.
Consequently:
Expiry, not revocation, is the load-bearing control. Attestations SHOULD be issued with short lifetimes and re-issued, so that withdrawal of an attester's opinion takes effect by lapse rather than requiring a positive act.
Consumers SHOULD NOT model revocation as a state distinct from absence unless they index CloseAttestationEvent. A reader that offers a "revoked" display state it can never populate from account data is lying about its coverage.
changeSchemaStatus sets isPaused on the whole schema — a kill switch for every attestation under it at once. Consumers SHOULD check it, and MUST treat a paused schema as no better than unattested.
3.5 Attester identity
The Attestation account carries both credential and signer. They are not interchangeable: signer is whichever of the credential's authorizedSigners signed this particular attestation, and that set is rotatable at will via changeAuthorizedSigners.
Trust sets are keyed on the credential, which is the stable identity of the attesting organisation. signer is operational detail, useful for forensics and useless for policy — keying trust on it means a routine key rotation silently invalidates every attestation an attester has issued.
The attester SHOULD NOT be the issuer. An issuer attesting to its own classification adds a signature but no independent verification. Self-attestation is permitted and MUST be detectable — consumers compare the credential authority and signer against the mint's authorities — so it can be surfaced or discounted per consumer policy.
3.6 Reference deployment
A working schema exists on devnet, created by npm run sas:devnet:
Account
Address
Credential
5Es4gSTWYemJxPMkWGYAi56Xzf2cSosJBRMaQaVVuxZq
Schema
ASE1gwae1gBPZctkdNXdyGJcmqwPMVW9iMHqs22bJa9p
Example attestation
G6qArVxuNwL9aC3EpTY443TfVTfyFmKwQhgmnd6rht9b
This is a draft artifact for implementers to read against, not a trust root and not a mainnet registration. Adoption-bar item 2 (§8) means a mainnet schema under a credential that is not solely the author's.
3.7 Trust sets are not part of this spec
This document does not name trusted attesters and does not establish a registry. Which attesters a consumer honours is consumer policy, and any list SHOULD be independently forkable. A specification that appoints its own authors as the trust root would not deserve adoption.
4. Layer 3 — data discovery and integrity
Extended property data cannot live on-chain. rwa.api points to a discovery document, not a live data endpoint:
https://issuer.example/.well-known/rwa.json
Static, cacheable, CORS-enabled, and it names the actual endpoints. This indirection matters because updating mint metadata costs an authority action and rent, so a URL written directly into a mint will go stale and stay stale.
4.1 Signing: detached, over raw bytes
The document is served with a detached ed25519 signature at .well-known/rwa.sig, computed over the exact bytes of rwa.json as served.
Raw-byte signing is deliberate. Signing a canonicalized JSON structure (JCS or otherwise) introduces a canonicalization implementation on both sides and every divergence between them is a signature bypass. Detached-over-bytes has no such surface.
The signing key MUST match discovery_signer in the attestation. TLS is not sufficient. TLS proves the reader reached the domain; it says nothing about who authored the content. If an issuer folds and its domain lapses, the re-registrant obtains a valid certificate and can serve authoritative-looking data for a live mint. A signature bound to an on-chain attested key cannot be re-acquired with the domain.
manifest is a multihash over the pinned document set (offering memorandum, appraisal, insurance certificate, SPV formation docs), which SHOULD also be content-addressed on IPFS or Arweave. Anything fetched that does not hash into the manifest is unverified and MUST be presented as such.
Live data MUST NOT feed authorization decisions and MUST be displayed with an "as of" timestamp.
5. Consumer requirements (normative)
A conforming consumer:
MUST check that an attestation's mint is the mint being assessed before relying on it. An attestation naming a different mint is not weak evidence about this token, it is no evidence about this token, and it MUST be disregarded rather than surfaced as a disagreement per §5.7. Without this check any genuine attestation can be replayed against any mint, which makes Layer 2 worth less than nothing: it converts an attester's reputation into a spoofing primitive. Note that rwa.attestation (§2) is written by the same authority as the rest of Layer 1 and so cannot itself establish the binding.
MUST NOT present unattested Layer 1 classification with the same visual treatment as attested classification.
MUST NOT use any field in this spec for authorization, transfer eligibility, or compliance decisions. Those are enforced on-chain by the token's own extensions. This spec is descriptive.
MUST distinguish expired attestation from no attestation. They mean different things: one issuer lapsed, the other never participated. Note that revoked is not a third state available to account readers (§3.4).
MUST display an "as of" timestamp on live-endpoint data.
SHOULD fetch discovery lazily — on a detail view, not on portfolio load. Eager fetching broadcasts a user's entire position set to every issuer whose tokens they hold, every time they open the wallet (§6).
SHOULD flag disagreement between rwa.* metadata and the attestation as a tamper signal rather than silently preferring one.
6. Privacy considerations
Parcel join. Covered in §2.4. This is the reason real estate warrants a profile of its own rather than folding into a generic RWA classification: no other asset class has a public, government-maintained, address-keyed registry sitting on the other side of the join.
Discovery phone-home. Fetching an issuer-controlled URL discloses the reader's IP, which mint they hold, and when they looked. Across several issuers this reconstructs a portfolio. Mitigations, in preference order: lazy fetch (§5.6); fetch via an indexer or proxy, which reduces N observers to one with a stated policy rather than eliminating the disclosure; cache aggressively.
Browser-extension wallets should note that fetching arbitrary issuer origins requires broad MV3 host permissions, which is both a review burden and a genuine attack-surface expansion.
7. Security considerations
Domain lapse / takeover — §4.1, mitigated by attested detached signing.
Metadata repoint — the update authority can rewrite Layer 1 at any time. Detected by comparing against the attestation (§5.7).
Attester compromise — bounded by expiry, since revocation is unobservable to account readers (§3.4). Consumers should support fast trust-set removal, which is the only mitigation fully under their own control.
Self-attestation laundering — an issuer standing up a shell attester. Detectable only through attester diligence; the spec makes attester identity legible (LEI, credential authority) so that diligence is possible.
Attestation replay — presenting a valid attestation issued for one mint alongside a different mint's metadata. The attestation's mint field is the binding; §5.1 makes checking it mandatory.
Enum squatting — mitigated by the closed rwa.class set.
8. Securities-law considerations (non-normative)
This section is informational. It does not impose conformance requirements on
consumers and does not change any Layer 1–3 mechanics. It exists because the
same discoverability that makes this standard useful — a mint's classification
being derivable by any observer without an indexer (§3.3) — sits close to a
line that some issuers are legally required not to cross, and an implementer
reading only the mechanical sections could wire the discovery layer in a way
that creates an offering-law problem the spec itself never intended.
Nothing in this document is legal advice. Issuers are responsible for their own
exemption analysis and should obtain their own counsel's approval before
publishing conforming metadata for a live offering.
8.1 The classification layers are descriptive, not an offer
Layers 1 and 2 describe what an asset is and what claim a holder has on
it. They are deliberately incapable of carrying price, availability,
minimum investment, projected return, valuation, or any term of an offering —
none of those fields exist in §2 or §3.1, and none should be smuggled into rwa.subclass, a discovery URL, or an unrecognized rwa.* key.
This is a design property with a legal consequence. Under U.S. law, an
exemption from registration under Regulation D that relies on Rule 506(b)
requires the issuer to avoid "general solicitation or general advertising"
(Securities Act Rule 502(c)). The prohibition targets the offering
communication — the pitch, its terms, anything that conditions the public mind
or arouses interest in the securities — not the mere on-chain existence or
discoverability of a security. A classification is a description, not a
conveyance (§Non-goals) and not an offer. Keeping the on-chain layers purely
classificatory is what keeps discoverability on the descriptive side of that
line.
The equivalent line is well-worn off-chain: an issuer's public website may
carry factual business information but not offering terms, projections, or
performance data, while the offering material itself sits behind a gated,
relationship-based channel. Layers 1–2 are the public site; Layer 3 is the
gate.
8.2 Layer 3 is the issuer's responsibility, at the issuer's exemption
The discovery document (rwa.api, §4) and everything it points to — offering
memoranda, appraisals, NAV endpoints, subscription materials — are issuer
content governed by the issuer's chosen exemption, not by this spec. The spec
specifies only where the pointer lives and how its integrity is proven
(§4.1); it says nothing about who may read the content behind it, and it must
not be read as permission to serve offering material to the public.
An issuer relying on Rule 506(b) SHOULD ensure that offering material behind rwa.api is not accessible to persons with whom the issuer lacks a
pre-existing, substantive relationship, and that the publicly fetchable
discovery document itself (the .well-known/rwa.json and its endpoint names) carries no offering terms. Gating the content while leaving the pointer public is consistent with the spec: the pointer is classification
infrastructure; the content is the offering.
An issuer relying on Rule 506(c), which permits general solicitation to
verified accredited investors, has more latitude in what Layer 3 may expose,
but assumes the corresponding obligation to take reasonable steps to verify
accredited status before sale. Note that the attestation primitive this spec
builds on (§3) is the same class of mechanism that the SEC staff has
recognized may be used to obtain and evidence the accredited-investor and
non-financing representations that support the streamlined 506(c) verification
approach — though this spec's rwa.classification.v1 schema is not itself an
eligibility attestation and MUST NOT be repurposed as one. Eligibility and
identity are SAS's domain and the token's own transfer logic (sRFC 00020), not
this classification schema.
8.3 The standard is exemption-neutral by construction
This document takes no position on which exemption an issuer uses, or on
whether a given token is even offered in the United States. That neutrality is
intentional and is the reason rwa.jurisdiction is a hint for consumers rather
than a control, and the reason no field encodes offering status. A consumer
MUST NOT infer from the presence of conforming metadata that a token is being
lawfully offered in the consumer's jurisdiction, that it is available for
purchase, or that any exemption is available to the reader — the metadata
describes the instrument, not the reader's ability to acquire it.
8.4 Summary of issuer obligations
An issuer publishing conforming metadata for a security:
MUST NOT place price, availability, minimum investment, projected or
historical return, valuation, or any offering term in any Layer 1 or Layer 2
field, or in the publicly fetchable body of the Layer 3 discovery document.
MUST treat Layer 3 offering content as governed by its own exemption, and
gate access to it accordingly — for a 506(b) offering, behind a
pre-existing substantive relationship; for a 506(c) offering, subject to
accredited-investor verification before sale.
MUST NOT rely on this spec, or on the discoverability it enables, as a
substitute for its own exemption analysis or counsel's approval.
SHOULD keep the classification attestation (rwa.classification.v1)
distinct from any eligibility, identity, or accreditation attestation; the
former describes the asset, the latter gate the holder.
These obligations run to the issuer. A conforming consumer incurs none of
them by reading, deriving, or displaying classification data — reading a
description of an instrument is not participation in its offering.
9 Governance
The author issues tokens in this category, which is a conflict worth stating plainly: a classification standard authored solely by an issuer invites the reading that it is a distribution land grab. Co-sponsorship is actively sought from the Solana Foundation RWA group, Metaplex, and at least one competing issuer, before this advances past draft.
Note on venue: sRFCs 00017 and 00020 predate the move to solana-foundation/SRFCs and are cited from the retired forum, which cannot be replied into. Discussion of this draft belongs in the GitHub thread.
Adoption bar before anyone should treat this as a standard:
Two independent issuers publishing conforming metadata.
One wallet that is not the author's rendering it.
Below that bar this is a blog post with a table in it.
10. Open questions
SAS field encoding.Resolved in §3.1 and verified on devnet (§3.6).
Should rwa.claim be multi-valued for hybrid instruments (converts, participating preferred)? Current view: no, use the senior characteristic and let discovery carry the detail. Multi-valued enums push complexity onto every reader.
Who maintains the rwa.subclass and property_commit namespace registries long-term? A flat file in a neutral repository is the proposal; it does not scale to contested namespaces.
Legacy SPL Token mints and indexer-free discovery.Resolved in §3.3: fixing the attestation PDA nonce to the subject mint makes the address derivable for any mint, so no pointer and no indexer are needed.
Is rwa.jurisdiction a single value in practice? Cross-border SPV structures may need a list.
11. Prior art
sRFC 00020 — permissioning and compliance mechanics; complementary.
ERC-3643 (T-REX) / ONCHAINID — the closest analogue. Its signed claim topics from trusted issuers are the model for Layer 2; SAS supplies the same shape natively on Solana.
ERC-1400 / CMTAT — security-token interfaces, again compliance-focused rather than classificatory.
ISO 10962 (CFI) — instrument classification. Well-established prior art for the rwa.claim axis and worth aligning with in a later revision.
ISO 17442 (LEI) / GLEIF — entity identity, verifiable against a free public API. The reason issuer_lei is preferred over a free-text issuer name.
Metaplex Token Metadata uri — an off-chain pointer that already exists. This proposal's Layer 3 is that pattern plus the two things it lacks: payload signing and hash pinning.
12. Reference implementation
src/rwa-classification.ts — a dependency-free parser, validator, and trust resolver. Pure functions over already-fetched RPC data; no crypto or RPC client is bundled, and signature verification is an injected seam so the module runs unchanged on native, web, and MV3.
Decoding a SAS account is deliberately not its job; that belongs to the SDK. The seam between them — decoded payload plus the account's native fields, in, AttestationView out — is exercised in src/rwa-schema.test.ts.
npm test runs the offline suites on node:test with native TypeScript stripping — no test runner dependency, so the module's dependency-free claim survives contact with its own test suite. A CLI validator (adoption bar item 1, §8) does not exist yet.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Posting this as a draft for comment. It is deliberately narrow, and it is meant to sit alongside sRFC 00020, not compete with it — 00020 owns permissioning, clawback, halts, and distributions, and none of that is in scope here.
What this adds. When classification came up in the 00020 thread, the resolution was that issuers should self-declare their asset type and implement matching logic. That works for an issuer's own product surface and breaks down for anyone consuming tokens they did not issue: a self-declared string with no attestation is trivially spoofed, and minting a lookalike with matching metadata costs a few cents. This proposal adds a small shared vocabulary and a binding from that vocabulary to someone accountable — nothing more.
What is already verifiable, because a spec with no implementation is a blog post with a table in it:
sas-lib@1.0.10and round-trips on devnet. Credential5Es4gSTWYemJxPMkWGYAi56Xzf2cSosJBRMaQaVVuxZq, schemaASE1gwae1gBPZctkdNXdyGJcmqwPMVW9iMHqs22bJa9p, example attestationG6qArVxuNwL9aC3EpTY443TfVTfyFmKwQhgmnd6rht9b.Three findings from building it that may be useful regardless of what happens to this proposal:
Vec<u8>orStringand say which.closeAttestationdeletes the account, so to anyone reading accounts a revoked attestation is byte-identical to one that never existed. Short expiry, not revocation, has to be the real control.What I am asking for. Co-sponsorship before this advances past draft — specifically from the Foundation RWA group, Metaplex, and at least one competing issuer. I issue tokens in this category, and a classification standard authored solely by an issuer invites the reading that it is a distribution land grab. That is also why §3.7 refuses to name trusted attesters and why the adoption bar in §8 is set where it is.
Open questions I would most like comment on: whether
rwa.claimshould be multi-valued for hybrid instruments (§9.2), who maintains the subclass and namespace registries long-term (§9.3), and whetherrwa.jurisdictionneeds to be a list for cross-border SPV structures (§9.5).Summary
A minimal, jurisdiction-agnostic convention for declaring what real-world asset a token represents, what claim the holder has on it, and where to find the extended data — bound to an expiring on-chain attestation so the declaration is verifiable rather than merely asserted.
This proposal deliberately does not specify transfer compliance mechanics. That is sRFC 00020's subject, and this is designed to sit alongside it.
Motivation
There is today no way for a wallet, indexer, or aggregator to determine that a Solana mint represents real estate — or any other asset class — without per-issuer bespoke integration.
sRFC 00020 covers permissioning, clawback, trading halts, and distributions. When classification came up in that thread, the resolution was that issuers should self-declare their asset type and implement matching logic. That is workable for an issuer's own product surface and unworkable for anyone consuming tokens they did not issue, because a self-declared string with no attestation is trivially spoofed. Any wallet that renders it as authoritative becomes a phishing surface: minting a token named
RVBNDwith matching metadata costs a few cents.Consumers currently fall back to name/symbol heuristics (unsafe), curated allowlists (unscalable, and each wallet maintains its own), or third-party aggregators (editorial, high-latency, poor small-issuer coverage).
The missing pieces are narrow: a small shared vocabulary, and a binding from that vocabulary to someone accountable.
Non-goals
Scope discipline is the main lesson from 00020's stall. Explicitly out of scope:
1. Layer overview
additionalMetadataon the mintLayer 1 alone is a convenience. Layer 1 without Layer 2 MUST NOT be presented as verified (§5). Layer 2 works standalone, which is how legacy SPL Token mints that cannot carry
additionalMetadataparticipate.2. Layer 1 — classification fields
Keys are namespaced
rwa.*to avoid collision with existing conventions.rwa.v1for this document.rwa.classrwa.claimrwa.jurisdictionUS-TX)rwa.issuer_leirwa.attestationrwa.subclassrwa.apiThree required keys. Consumers MUST ignore unrecognized
rwa.*keys rather than rejecting the token, so the vocabulary can grow without breaking readers.2.1
rwa.class— what the asset isClosed set. An open set is unfilterable and therefore useless for the routing and grouping decisions consumers need to make.
Anything unlisted uses
otherplus arwa.subclass. Additions to this set require a spec version bump.2.2
rwa.claim— what the holder ownsClosed set. This axis is orthogonal to
rwa.classand omitting it is the most common failure in naive taxonomies.A first-lien mortgage note secured by an apartment building and an equity stake in that same building are both
real-estate, with inverted risk profiles, opposite behaviour in a downturn, and different regulatory treatment. A consumer that buckets them together on the strength ofrwa.classalone actively misleads its users. Both fields are required so this cannot be skipped.direct-titleis reserved for tokens where the token itself is the instrument of title under some jurisdiction's law. It is expected to be rare and SHOULD carry an attestation naming the recording authority.2.3
rwa.subclass— open registryExtensible, maintained as a flat list in the reference repository, additions by PR without a version bump. For
real-estate, the initial vocabulary aligns with the NCREIF/NAREIT core property types rather than inventing one:2.4 Property identification
Property identifiers are not carried in Layer 1. They are jurisdictional (US county APN, UK UPRN, FR cadastre) and they are a privacy hazard: a public parcel ID joined against public token balances and public property records deanonymizes a holder's position and, by extension, their net worth.
Where a property reference is needed it appears in the attestation (§3) as a commitment:
with
namespacedrawn from a registry of the formus-tx-travis-apn,gb-uprn,fr-cadastre. The preimage is disclosed off-chain to parties with standing — regulators, auditors, holders under NDA — not to chain observers.3. Layer 2 — attestation
Layer 2 uses the Solana Attestation Service (program
22zoJMtdu4tQc2PzL74ZUT7FrwgB1Udec8DdW4yw4BdG, Apache-2.0, maintained by the Solana Foundation). No new program is required or proposed. Field encodings below are pinned againstsas-lib@1.0.10and verified end-to-end on devnet (§3.6).A Credential identifies the attesting authority — a transfer agent, auditor, regulated registry, or exchange. A Schema named
rwa.classification.v1defines the claim. An Attestation binds a mint to a classification.3.1 Schema layout
A SAS
Schemaaccount storesfieldNamesalongside alayoutbyte array, one compact type code per field. The codes are the SDK's, not this spec's; the relevant subset is12=Stringand13=Vec<u8>. Attestation data is Borsh-encoded against the struct those two arrays describe.rwa.classification.v1is exactly:mintVec<u8>classStringclaimStringsubclassStringjurisdictionStringissuer_leiStringproperty_commitVec<u8>discovery_urlStringdiscovery_signerVec<u8>Field order is normative — Borsh is positional, and
layoutcarries no names of its own beyond the parallelfieldNamesarray.Pubkeys are 32 raw bytes, not base58 strings. SAS has no pubkey type code, so a key has to be carried as either
Vec<u8>orString. This spec picks raw bytes: it is canonical, it is half the size, and it removes base58 as a place where two implementations can disagree. Consumers comparing against a base58 address MUST encode the attested bytes rather than decoding the address, so that a malformed value fails the comparison instead of throwing.Vec<u8>is length-prefixed. A 32-byte value occupies 36 bytes on the wire.property_commitis the one field that MAY be empty rather than zero-filled; prefer empty, since 32 zero bytes is a valid-looking commitment to nothing.A fully populated attestation serializes to 228 bytes.
3.2 Expiry is the account's, not the schema's
expires_atis deliberately absent from the schema. The SASAttestationaccount already carries a nativeexpiryfield, set through thecreateAttestationinstruction. Carrying a second copy inside the Borsh payload would create two sources of truth that can disagree, with no rule for which wins — and the native one is the only one the program itself can enforce. Consumers MUST read expiry from the account.Expiry is mandatory. Appraisals go stale, SPVs dissolve, transfer agents get replaced, registrations lapse. An attestation without expiry is a claim about the past presented as a claim about the present.
3.3 Discovery without an indexer
The
AttestationPDA derives from(credential, schema, nonce), wherenonceis free-form. This spec fixesnonce= the subject mint.That one choice makes attestations discoverable by derivation rather than search. A consumer holding a trust set already knows each attester's credential, and the schema PDA follows from it, so for any mint it can compute the exact attestation address and fetch it — one derivation and one account read per trusted attester, with no indexer, no log scanning, and no dependence on
rwa.attestationbeing present or honest.It follows that
rwa.attestation(§2) is a convenience hint, never the authority: it is written by the same update authority as the rest of Layer 1. A consumer MUST NOT trust an attestation solely because Layer 1 pointed at it.This also resolves how legacy SPL Token mints participate. They cannot carry
additionalMetadata, but they need no pointer — the derivation is over the mint address, which every token has.3.4 Revocation is deletion, and that has consequences
SAS has no
revokeAttestationinstruction. Revocation iscloseAttestation, which deletes the account and emits aCloseAttestationEventcarrying the data that was destroyed.This is worth stating plainly because it defeats the obvious reading of §5.4: to a consumer reading accounts, a revoked attestation and one that never existed are byte-for-byte identical. Only a party consuming program logs can tell them apart, and logs age out of most RPC providers.
Consequently:
CloseAttestationEvent. A reader that offers a "revoked" display state it can never populate from account data is lying about its coverage.changeSchemaStatussetsisPausedon the whole schema — a kill switch for every attestation under it at once. Consumers SHOULD check it, and MUST treat a paused schema as no better than unattested.3.5 Attester identity
The
Attestationaccount carries bothcredentialandsigner. They are not interchangeable:signeris whichever of the credential'sauthorizedSignerssigned this particular attestation, and that set is rotatable at will viachangeAuthorizedSigners.Trust sets are keyed on the credential, which is the stable identity of the attesting organisation.
signeris operational detail, useful for forensics and useless for policy — keying trust on it means a routine key rotation silently invalidates every attestation an attester has issued.The attester SHOULD NOT be the issuer. An issuer attesting to its own classification adds a signature but no independent verification. Self-attestation is permitted and MUST be detectable — consumers compare the credential authority and
signeragainst the mint's authorities — so it can be surfaced or discounted per consumer policy.3.6 Reference deployment
A working schema exists on devnet, created by
npm run sas:devnet:5Es4gSTWYemJxPMkWGYAi56Xzf2cSosJBRMaQaVVuxZqASE1gwae1gBPZctkdNXdyGJcmqwPMVW9iMHqs22bJa9pG6qArVxuNwL9aC3EpTY443TfVTfyFmKwQhgmnd6rht9bThis is a draft artifact for implementers to read against, not a trust root and not a mainnet registration. Adoption-bar item 2 (§8) means a mainnet schema under a credential that is not solely the author's.
3.7 Trust sets are not part of this spec
This document does not name trusted attesters and does not establish a registry. Which attesters a consumer honours is consumer policy, and any list SHOULD be independently forkable. A specification that appoints its own authors as the trust root would not deserve adoption.
4. Layer 3 — data discovery and integrity
Extended property data cannot live on-chain.
rwa.apipoints to a discovery document, not a live data endpoint:Static, cacheable, CORS-enabled, and it names the actual endpoints. This indirection matters because updating mint metadata costs an authority action and rent, so a URL written directly into a mint will go stale and stay stale.
4.1 Signing: detached, over raw bytes
The document is served with a detached ed25519 signature at
.well-known/rwa.sig, computed over the exact bytes ofrwa.jsonas served.Raw-byte signing is deliberate. Signing a canonicalized JSON structure (JCS or otherwise) introduces a canonicalization implementation on both sides and every divergence between them is a signature bypass. Detached-over-bytes has no such surface.
The signing key MUST match
discovery_signerin the attestation. TLS is not sufficient. TLS proves the reader reached the domain; it says nothing about who authored the content. If an issuer folds and its domain lapses, the re-registrant obtains a valid certificate and can serve authoritative-looking data for a live mint. A signature bound to an on-chain attested key cannot be re-acquired with the domain.4.2 Document shape
{ "version": "1", "mint": "Rv8nDq4pKmT2xLcYbW6sJ9fHgA3eZuN5tQrX7vMkPd1", "issued_at": "2026-08-14T00:00:00Z", "expires_at": "2026-11-14T00:00:00Z", "manifest": "bafkrei...", "endpoints": { "summary": "https://api.issuer.example/v1/assets/Rv8n.../summary", "documents": "https://api.issuer.example/v1/assets/Rv8n.../documents", "nav": "https://api.issuer.example/v1/assets/Rv8n.../nav" } }manifestis a multihash over the pinned document set (offering memorandum, appraisal, insurance certificate, SPV formation docs), which SHOULD also be content-addressed on IPFS or Arweave. Anything fetched that does not hash into the manifest is unverified and MUST be presented as such.4.3 Data classes by cadence
Live data MUST NOT feed authorization decisions and MUST be displayed with an "as of" timestamp.
5. Consumer requirements (normative)
A conforming consumer:
mintis the mint being assessed before relying on it. An attestation naming a different mint is not weak evidence about this token, it is no evidence about this token, and it MUST be disregarded rather than surfaced as a disagreement per §5.7. Without this check any genuine attestation can be replayed against any mint, which makes Layer 2 worth less than nothing: it converts an attester's reputation into a spoofing primitive. Note thatrwa.attestation(§2) is written by the same authority as the rest of Layer 1 and so cannot itself establish the binding.rwa.*metadata and the attestation as a tamper signal rather than silently preferring one.6. Privacy considerations
Parcel join. Covered in §2.4. This is the reason real estate warrants a profile of its own rather than folding into a generic RWA classification: no other asset class has a public, government-maintained, address-keyed registry sitting on the other side of the join.
Discovery phone-home. Fetching an issuer-controlled URL discloses the reader's IP, which mint they hold, and when they looked. Across several issuers this reconstructs a portfolio. Mitigations, in preference order: lazy fetch (§5.6); fetch via an indexer or proxy, which reduces N observers to one with a stated policy rather than eliminating the disclosure; cache aggressively.
Browser-extension wallets should note that fetching arbitrary issuer origins requires broad MV3 host permissions, which is both a review burden and a genuine attack-surface expansion.
7. Security considerations
mintfield is the binding; §5.1 makes checking it mandatory.rwa.classset.8. Securities-law considerations (non-normative)
This section is informational. It does not impose conformance requirements on
consumers and does not change any Layer 1–3 mechanics. It exists because the
same discoverability that makes this standard useful — a mint's classification
being derivable by any observer without an indexer (§3.3) — sits close to a
line that some issuers are legally required not to cross, and an implementer
reading only the mechanical sections could wire the discovery layer in a way
that creates an offering-law problem the spec itself never intended.
Nothing in this document is legal advice. Issuers are responsible for their own
exemption analysis and should obtain their own counsel's approval before
publishing conforming metadata for a live offering.
8.1 The classification layers are descriptive, not an offer
Layers 1 and 2 describe what an asset is and what claim a holder has on
it. They are deliberately incapable of carrying price, availability,
minimum investment, projected return, valuation, or any term of an offering —
none of those fields exist in §2 or §3.1, and none should be smuggled into
rwa.subclass, a discovery URL, or an unrecognizedrwa.*key.This is a design property with a legal consequence. Under U.S. law, an
exemption from registration under Regulation D that relies on Rule 506(b)
requires the issuer to avoid "general solicitation or general advertising"
(Securities Act Rule 502(c)). The prohibition targets the offering
communication — the pitch, its terms, anything that conditions the public mind
or arouses interest in the securities — not the mere on-chain existence or
discoverability of a security. A classification is a description, not a
conveyance (§Non-goals) and not an offer. Keeping the on-chain layers purely
classificatory is what keeps discoverability on the descriptive side of that
line.
The equivalent line is well-worn off-chain: an issuer's public website may
carry factual business information but not offering terms, projections, or
performance data, while the offering material itself sits behind a gated,
relationship-based channel. Layers 1–2 are the public site; Layer 3 is the
gate.
8.2 Layer 3 is the issuer's responsibility, at the issuer's exemption
The discovery document (
rwa.api, §4) and everything it points to — offeringmemoranda, appraisals, NAV endpoints, subscription materials — are issuer
content governed by the issuer's chosen exemption, not by this spec. The spec
specifies only where the pointer lives and how its integrity is proven
(§4.1); it says nothing about who may read the content behind it, and it must
not be read as permission to serve offering material to the public.
An issuer relying on Rule 506(b) SHOULD ensure that offering material behind
rwa.apiis not accessible to persons with whom the issuer lacks apre-existing, substantive relationship, and that the publicly fetchable
discovery document itself (the
.well-known/rwa.jsonand its endpointnames) carries no offering terms. Gating the content while leaving the
pointer public is consistent with the spec: the pointer is classification
infrastructure; the content is the offering.
An issuer relying on Rule 506(c), which permits general solicitation to
verified accredited investors, has more latitude in what Layer 3 may expose,
but assumes the corresponding obligation to take reasonable steps to verify
accredited status before sale. Note that the attestation primitive this spec
builds on (§3) is the same class of mechanism that the SEC staff has
recognized may be used to obtain and evidence the accredited-investor and
non-financing representations that support the streamlined 506(c) verification
approach — though this spec's
rwa.classification.v1schema is not itself aneligibility attestation and MUST NOT be repurposed as one. Eligibility and
identity are SAS's domain and the token's own transfer logic (sRFC 00020), not
this classification schema.
8.3 The standard is exemption-neutral by construction
This document takes no position on which exemption an issuer uses, or on
whether a given token is even offered in the United States. That neutrality is
intentional and is the reason
rwa.jurisdictionis a hint for consumers ratherthan a control, and the reason no field encodes offering status. A consumer
MUST NOT infer from the presence of conforming metadata that a token is being
lawfully offered in the consumer's jurisdiction, that it is available for
purchase, or that any exemption is available to the reader — the metadata
describes the instrument, not the reader's ability to acquire it.
8.4 Summary of issuer obligations
An issuer publishing conforming metadata for a security:
historical return, valuation, or any offering term in any Layer 1 or Layer 2
field, or in the publicly fetchable body of the Layer 3 discovery document.
gate access to it accordingly — for a 506(b) offering, behind a
pre-existing substantive relationship; for a 506(c) offering, subject to
accredited-investor verification before sale.
substitute for its own exemption analysis or counsel's approval.
rwa.classification.v1)distinct from any eligibility, identity, or accreditation attestation; the
former describes the asset, the latter gate the holder.
These obligations run to the issuer. A conforming consumer incurs none of
them by reading, deriving, or displaying classification data — reading a
description of an instrument is not participation in its offering.
9 Governance
The author issues tokens in this category, which is a conflict worth stating plainly: a classification standard authored solely by an issuer invites the reading that it is a distribution land grab. Co-sponsorship is actively sought from the Solana Foundation RWA group, Metaplex, and at least one competing issuer, before this advances past draft.
Note on venue: sRFCs 00017 and 00020 predate the move to solana-foundation/SRFCs and are cited from the retired forum, which cannot be replied into. Discussion of this draft belongs in the GitHub thread.
Adoption bar before anyone should treat this as a standard:
Below that bar this is a blog post with a table in it.
10. Open questions
SAS field encoding.Resolved in §3.1 and verified on devnet (§3.6).rwa.claimbe multi-valued for hybrid instruments (converts, participating preferred)? Current view: no, use the senior characteristic and let discovery carry the detail. Multi-valued enums push complexity onto every reader.rwa.subclassandproperty_commitnamespace registries long-term? A flat file in a neutral repository is the proposal; it does not scale to contested namespaces.Legacy SPL Token mints and indexer-free discovery.Resolved in §3.3: fixing the attestation PDA nonce to the subject mint makes the address derivable for any mint, so no pointer and no indexer are needed.rwa.jurisdictiona single value in practice? Cross-border SPV structures may need a list.11. Prior art
rwa.claimaxis and worth aligning with in a later revision.issuer_leiis preferred over a free-text issuer name.uri— an off-chain pointer that already exists. This proposal's Layer 3 is that pattern plus the two things it lacks: payload signing and hash pinning.12. Reference implementation
src/rwa-classification.ts— a dependency-free parser, validator, and trust resolver. Pure functions over already-fetched RPC data; no crypto or RPC client is bundled, and signature verification is an injected seam so the module runs unchanged on native, web, and MV3.Decoding a SAS account is deliberately not its job; that belongs to the SDK. The seam between them — decoded payload plus the account's native fields, in,
AttestationViewout — is exercised insrc/rwa-schema.test.ts.src/rwa-classification.tssrc/rwa-classification.test.tssrc/rwa-schema.test.tsscripts/sas-devnet.mjsnpm testruns the offline suites onnode:testwith native TypeScript stripping — no test runner dependency, so the module's dependency-free claim survives contact with its own test suite. A CLI validator (adoption bar item 1, §8) does not exist yet.All reactions