Components
Simple Page is a monorepo with contracts, a frontend app, shared libraries, a CLI, and a Node service.
Smart Contracts
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 USDper 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
SimplePageNFT.
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
contenthashand 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 /pageuploads for staged page CARs.GET /pagelightweight CAR retrieval.GET /filelocal raw block retrieval.GET /historyhistory CAR retrieval.GET/POST /refs/:ensNameoff-chain draft refs.GET/POST /capabilities/:ensNameSIWE agent capabilities.- Allow/block lists.
- Peer discovery and ref sync.
- Finalization when ENS
ContenthashChangedevents 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/.