Skip to content

feat: read Platform 4.2 contracts (declared references and protocol 14 keywords) - #1

Merged
QuantumExplorer merged 1 commit into
mainfrom
feat/platform-4-2
Sep 28, 2026
Merged

QuantumExplorer merged 1 commit into
mainfrom
feat/platform-4-2

Conversation

@QuantumExplorer

@QuantumExplorer QuantumExplorer commented Sep 28, 2026 •

Copy link
Copy Markdown
Member

Basic explanation

What this does: The visualizer draws a data contract as a diagram: one box per document type, with arrows between types that point at each other. Until now the arrows were guesses from field names (a field called authorId probably points at author), because contracts had no way to say what a field points at. Platform 4.2 (protocol version 14) added that: refersTo and its relatives state exactly what an identifier must point at, and the platform checks it on every write. This PR reads those declarations and draws them as real arrows. It also shows every other contract keyword added in 4.2 (document expiry, frozen fields, fees, moderation, new index kinds and more), explains each one in plain words with a link to the Dash Platform Book, and adds a menu of example contracts.

Value: The diagram of a 4.2 contract shows what the contract actually enforces instead of what its field names suggest. For example, the moderation charters contract goes from 10 guessed arrows (one pointing at the wrong type, three only because two types index the same field) to 17 declared ones plus 1 remaining guess, for the one identifier that declares nothing. Contracts from 4.2 networks can now be loaded at all (the old SDK cannot decode them). The page also opens much faster: the SDK is downloaded only when you fetch a contract from a network, so the first load drops from 13.3 MB to 1.9 MB.

Risks: Low. The site is read-only and has no backend. The SDK is pinned to a prerelease, @dashevo/evo-sdk 4.2.0-beta.4 (beta.5 on npm cannot be installed: it depends on a @dashevo/wasm-sdk 4.2.0-beta.5 that was never published). Loading from testnet and mainnet, which still run 4.1, was checked by hand with this SDK. Merging to main redeploys the live Pages site.

What changed

Declared references

  • refersTo on a property, refersTo on a typed array's items, and the document type level ownerRefersTo / creatorRefersTo become solid edges that leave from the exact field row that declares them (a per-field React Flow handle).
  • Edges are coloured by what they point at: a document type of this contract, another contract's document type, an identity, an identity key, a data contract, a token. Non-document targets and other contracts' types get their own nodes; system contracts are named (DPNS, DashPay, ...), and the inspector offers "Open this contract".
  • Labels carry multiplicity (1, 0..1, 0..∗; (1,1), (0,1), (0,n) in Merise) and how the target is found: via <index> for a lookup, ∈ <list> for a list element (the edge ends on the list field), <purpose> key, deletable, anyOf 1/2. An anyOf / allOf gives one edge per operand.
  • The name heuristics still run, only for fields that declare nothing, never for $ system fields (every type indexes $ownerId, which produced noise), and are drawn dashed and labelled inferred.

Protocol version 14 keywords

  • Chips under each document type header: ttl 30d, no edits, no delete, mods delete ≤1w, owner creates, transferable, for sale, history, logged, fees, token cost, count / Σ x / id ranges, sig critical, enc keys / dec keys. Index-only types get a dashed border and their own stereotype.
  • Field chips: fixed (immutable), set once (immutableAllowSetting), transient, v2+ (requiredSince), enc (encryptedFor), ≠ $ownerId (distinctFrom), payload (entryPayload). Nested objects are indented under their parent; typed arrays read string[] / identifier[]; a $ref shows its schemaDefs name.
  • Index chips: contested, count, Σ x, range, top-K count/sum/avg, window 1d/1h (timeRange), → $ownerId (terminal), prealloc, skip absent, no nulls.
  • propertyConstraints get their own compartment, rendered as formulas.
  • The metadata panel adds keywords, description, timestamps, config, moderation (lists, who moderates, election windows, moderated types) and schemaDefs.
  • The inspector explains every keyword in a sentence and links its Dash Platform Book chapter.

Examples and validation

  • An Examples menu and a start page of example cards: a marketplace showcase written for this PR (not registered anywhere) that uses the 4.2 keywords together, the moderation charters system contract, index-only likes and tips from the Drive test suite, DPNS, DashPay, app-connect, keyword search, withdrawals, and dash-qa (no declared references, so every edge is inferred).
  • npm run validate:examples runs every example through DataContract.fromJSON(json, true, 14) (the platform's meta-schema and parser, via the SDK) and checks src/model/fixtures/sdk-references.json, the SDK's own reading of their references. A unit test asserts the diagram's parser finds exactly those references. The deploy workflow runs it.

Load a contract from a link (?url=)

  • ?url=<link>, or a link typed into the contract id box, fetches a contract JSON file and diagrams it like pasted JSON, without the SDK. A contract in a pull request that is not registered yet opens from one shareable link, for example ?url=https://github.com/PastaPastaPasta/yappr/blob/429da9df940ff3196858982d4b7af81331180f3f/contracts/yappr-social-contract-v9.json (17 types, 15 declared references, 9 property constraints).
  • GitHub page links (github.com/<owner>/<repo>/blob|raw/<ref>/<path>) are fetched from raw.githubusercontent.com; other hosts must allow cross-origin reads. Only http(s); files over 5 MB are refused; HTTP errors, CORS failures and non-JSON bodies each get a clear message.
  • The Vite dev server reads ?url as its own asset-import query and answered such page requests with 403; a dev-only plugin in vite.config.ts serves the app for them. Static hosting (Pages) needs nothing.

Other

  • The SDK is imported on the first network fetch (import('./client')); connection pooling moved to src/sdk/pool.ts so the toolbar can reset it without loading the SDK.
  • Legend with filters (declared, inferred, platform objects), a devnet name field, theme-aware minimap and controls, a second layout pass with measured node sizes, deep links ?example=<key> and ?devnet=<name>.

Before and after

The moderation charters contract, joinRequest.submittedCharterId:

"refersTo": {
  "type": "permanentDocument",
  "documentType": "submittedCharter",
  "propertyAgreement": { "recipientId": "$ownerId" }
}
  • Before: a dashed arrow from the joinRequest box to submittedCharter, labelled ∗ — 1, "inferred, high confidence: joinRequest.submittedCharterId is an identifier named after submittedCharter". Nothing about the agreement. recipientId (an identity key reference) had no arrow. submittedCharter.targetContractId (a reference to the contract being moderated) had a wrong one, to electedCharter, because its name matched that type's unique key. Types that merely both index $ownerId got a weak arrow.
  • After: a solid arrow from the submittedCharterId row to submittedCharter, labelled 1. The inspector says "the value must be the id of a "submittedCharter" document, a type whose documents are never deleted" and "must agree: recipientId (here) = $ownerId (there)". recipientId has its own arrow to an Identity key node, labelled 1 · decryption key, and targetContractId one to a Data contract node.

The marketplace showcase, listing:

  • Before: the header showed only the name. ttl, moderator deletion, action fees, immutable, requiredSince and the property constraint were not shown anywhere.
  • After: chips ttl 30d, mods delete ≤1w, fees, count; shopId marked fixed, sku marked set once, photoHash marked v2+, price typed credits (its $ref); a constraints compartment reading saleBelowPrice: salePrice ?? 0 < price.

Testing

  • npm test: 65 tests pass, including the parser-equals-SDK check for all 9 examples, refersTo edge shapes (anyOf split, list element target, lookup, external and platform nodes, optional multiplicity), constraint formulas, keyword chips, the React Flow mapping (every edge starts at a handle its node renders) and link handling (GitHub blob to raw, scheme check, HTTP / CORS / non-JSON errors).
  • npm run typecheck, npm run build, npm run validate:examples: clean.
  • By hand in the browser, light and dark themes: every example, both views, the inspector on fields, indexes, constraints, edges and external nodes. Live loads through the new SDK:
    • moutai devnet (4.2.0-beta.4, protocol version 14): moderation charters EG7RGfV8fDTayC2FyVr8HwdpJh3fXDbVztcfE94UmN88, 7 types, 17 declared references, the same as the bundled copy;
    • testnet: DPNS;
    • mainnet: DashPay.
  • ?url= by hand: a GitHub commit link and a branch link with a slash in the ref (beta5/contracts) through the dev server and through the production build served as static files under /contract-visualizer/ (the SDK chunk is not downloaded); a 404 and a host without CORS show their messages.

Notes

  • The 4.2.0-beta.4 parser accepts only a plain comparison at the top of a propertyConstraints rule; it refuses anyOf, present and not there, which the v4.2-dev book documents. The showcase keeps to simple comparisons so it validates; the formula renderer handles the full grammar (unit-tested with the book's examples).
  • References are read from the raw schema rather than from the SDK's parsed documentReferences, so pasted contracts that are not registered yet diagram the same way. The fixture test keeps the two in step.

🤖 Generated with Claude Code

…4 keywords)

Bump @dashevo/evo-sdk to 4.2.0-beta.4 so contracts from protocol version 14
networks decode (older SDKs refuse the version 2 contract config), and draw
what the 4.2 contract language states instead of guessing it.

- refersTo, items.refersTo, ownerRefersTo and creatorRefersTo become declared
  edges that leave from the field declaring them, coloured by target kind,
  labelled with multiplicity and how the target is found (lookup index, list
  element, key purpose, deletable). anyOf / allOf give one edge per operand.
  Identities, identity keys, contracts, tokens and other contracts' document
  types get their own nodes; system contracts are named.
- Name-based inference stays for fields that declare nothing, never for
  system fields, and is drawn dashed.
- Document type, field and index keywords of protocol version 14 show as
  chips (ttl, immutable, transient, requiredSince, encryptedFor, distinctFrom,
  actionFees, tokenCost, moderator deletion, index-only, ranked and
  time-range indexes, ...); propertyConstraints render as formulas;
  moderation config shows in the metadata panel; the inspector explains each
  keyword and links its Dash Platform Book chapter.
- Bundled examples (marketplace showcase, moderation charters, index-only
  likes, system contracts, dash-qa). scripts/validate-examples.mjs runs each
  through DataContract.fromJSON(json, true, 14) and checks the SDK's reading
  of their references, which a unit test compares with the diagram's parser;
  CI runs it.
- The SDK is imported on the first network fetch only: the initial bundle
  goes from 13.3 MB to 1.9 MB.
- Legend with filters, devnet name field, theme-aware React Flow chrome,
  re-layout with measured node sizes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 28, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 99348b09-7502-40bd-ace7-18a34b21fb87


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@QuantumExplorer
QuantumExplorer merged commit f5aa9c0 into main Sep 28, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant