Components

Simple Page is a monorepo with contracts, a frontend app, shared libraries, a CLI, and a Node service.

Smart Contracts

Relationships between the SimplePage, SimplePageManager, and TokenRenderer contracts and the NFTs they issue.

Mainnet deployments:

Contract Etherscan
SimplePage 0x99acdb2946b7240aac9aeb290cc0af145c48007e
SimplePageManager 0x17d02345c9f5949fb1c8262c210d51e81e1d78d6
TokenRendererV3 0x7f1FDCC37177D0127BD94Da522d969257C7E3958

SimplePage

SimplePage is an ERC721 contract. Each subscribed ENS domain maps to a token ID derived from keccak256(domain).

The token stores PageData:

struct PageData {
    string domain;
    uint256[] units;
}

Each unit is an expiry timestamp. The current manager updates unit 0 when a subscription is purchased or extended.

SimplePageManager

SimplePageManager handles subscription payments.

  • Price is 12 USD per year, paid in ETH.
  • ETH/USD conversion uses a Chainlink price feed.
  • Extra ETH is refunded.
  • Renewals extend from the current expiry when a subscription is still active.
  • Successful subscriptions mint or update the SimplePage NFT.

TokenRenderer

TokenRendererV3 renders on-chain NFT metadata and SVG imagery for subscribed pages. It includes the domain, active unit count, unit expiry traits, and a foam identicon.

Frontend

Location: frontend/

The frontend is a React app that ships inside every Simple Page site.

Current routes include:

Route Purpose
/ View published content.
/spg-edit Markdown editor with side-by-side preview.
/spg-pages Page creation, deletion, restore, and status.
/spg-files File uploads, folders, previews, copy paths, restore.
/spg-publish Stage changes and publish an ENS contenthash transaction.
/spg-subscription Subscribe, renew, or donate.
/spg-settings Appearance, search, donation notice, and local cache controls.
/spg-history Timeline of indexed published roots with restore actions.
/spg-agents Authorize CLI agent keys with SIWE capabilities.
/spg-drafts Review and publish signed off-chain drafts.

The frontend reads the current domain from meta[name="ens-domain"] and uses @simplepg/repo for all content operations.

Repo Library

Location: packages/repo/

@simplepg/repo is the canonical content engine.

It manages:

  • Markdown and rendered HTML pages.
  • Local browser edits.
  • File changes under _files/.
  • Settings and generated theme.css.
  • RSS feed generation.
  • Navigation sidebar metadata.
  • Template upgrades from new.simplepage.eth.
  • History access through the Node API.
  • Ref and capability access for drafts.
  • CAR construction for staged publishes and drafts.

Common Utilities

Location: packages/common/

@simplepg/common contains shared ENS, IPFS, IPLD, contenthash, Node endpoint discovery, SIWE capability, and ref-signing utilities.

Important responsibilities:

  • Resolve ENS contenthash and text records.
  • Convert IPFS CIDs to ENS contenthash values.
  • Build and traverse CARs.
  • Provide browser UnixFS storage backed by memory, IndexedDB, and localStorage WAL.
  • Verify off-chain ref and capability signatures.

Simple Page Node

Location: packages/node/

The Node provides IPFS storage, blockchain indexing, REST endpoints, and peer synchronization.

It handles:

  • POST /page uploads for staged page CARs.
  • GET /page lightweight CAR retrieval.
  • GET /file local raw block retrieval.
  • GET /history history CAR retrieval.
  • GET/POST /refs/:ensName off-chain draft refs.
  • GET/POST /capabilities/:ensName SIWE agent capabilities.
  • Allow/block lists.
  • Peer discovery and ref sync.
  • Finalization when ENS ContenthashChanged events are indexed.

CLI

Location: packages/cli/

The CLI supports two families of workflows:

  • simplepage repo ... for cloning and editing Simple Page markdown repos locally.
  • simplepage drafts ... for pushing raw static builds or reviewing signed draft refs.

See CLI Reference for current commands.

Published File System

Simple Page roots are UnixFS directories stored on IPFS.

├── index.md
├── index.html
├── about/
│   ├── index.md
│   └── index.html
├── _files/
├── _prev/
│   └── 0/
├── _template.html
├── settings.json
├── theme.css
├── manifest.json
├── manifest.webmanifest
├── rss.xml
├── sidenav.json
└── _redirects

Every publish creates a new root CID. Previous roots remain addressable and are linked recursively through _prev/0/.