ThesisLock anchors a SHA-256 hash of any document on the Stacks blockchain, giving you a permanent, verifiable timestamp without ever exposing the file. Drop a document into the page, the browser hashes it locally, you sign a transaction with your Stacks wallet, and anyone can later visit a verification URL to confirm when it was anchored, by which wallet, and what label was attached.
- App: thesis-lock.vercel.app
- Docs: thesis-lock.vercel.app/docs
- Deployer:
SP3QS6X01XKTYC84BHA0J567CZTAH67BJHN88FNVM
- Single file anchoring with optional ASCII label up to 64 characters.
- Anchor templates at
/templates: structured label formats for papers, legal documents, code releases, datasets, and certificates, with a live label preview and parsed fields shown on verify and history pages. - Batch anchoring of up to ten files in a single transaction.
- Per-wallet anchor history at
/anchors, populated automatically when you anchor. - Unified activity log at
/activity: a chronological timeline of every interaction across all five contracts (anchors, batches, registry entries, proof mints, and group actions), with category filters, date separators, and infinite scroll. Also exposed as JSON at/api/activity. - Anchor groups at
/groups: create a named group, add members, and anchor documents under a shared, on-chain history. - Client-side SHA-256 hashing. The file never leaves your device.
- Public verification at
/v/<hash>with file re-upload check, plus bulk verification at/verify-bulk. - Formal verification reports in HTML, JSON, and CSV at
/report: a multi-document audit report with a table of contents, summary statistics, and per-hash verification details across every contract, generated from dropped files, pasted hashes, or your own anchors. Exposed as JSON, HTML, or CSV at/api/report. - Side-by-side anchor comparison at
/compare: drop or paste two hashes to see which was anchored first, the estimated time gap, and how their owner, label, source, template, and proof differ, with highlighted differences and shareable comparison links. Exposed as JSON at/api/compare. - Public feed at
/feedand cross-contract search at/search. - Real-time live updates with event ticker and auto-refreshing pages: a single visibility-aware poller streams new on-chain events into a scrolling activity ticker, prepends new anchors to the feed, ticks the stats counters up live, and surfaces fresh calls in the contract explorer, all pausable from any Live indicator.
- Public wallet profiles at
/u/<principal>: anyone's anchoring history as a verifiable portfolio, with anchor, batch, group, and proof totals, recent anchors, and the document types they anchor. Exposed as JSON at/api/profile/<principal>and as a shields-style badge at/api/profile-badge/<principal>. - Embeddable badges at
/embed: a shields-style "Verified on Stacks" SVG badge (/api/badge/<hash>) and a social sharing card (/api/card/<hash>) for any anchored hash. - Optional soulbound proof NFTs (SIP-009) as permanent in-wallet evidence of an anchor.
- Developer Portal at
/developerswith an API playground, key management, and integration guides: pick any GET endpoint and send live requests with a copy-ready curl command, create scoped API keys (stored client-side), and copy ready-to-run examples for JavaScript, Python, cURL, GitHub Actions, and CI/CD. - Document and wallet watchlist with status monitoring at
/watchlist: save document hashes, wallets, and groups, then track whether a hash has been anchored or a wallet or group has new anchors, with auto-check on load, manual refresh, and update badges on the nav link and dashboard widget. Stored entirely in the browser. - Unified notification center at
/notifications: aggregates transaction confirmations, watchlist status changes, new protocol anchors, and group activity in one place, with a corner bell showing unread count and recent items, optional browser push for important events, a synthesized sound alert, and per-type preferences. Stored entirely in the browser. - Document collections for organizing and sharing anchored documents at
/collections: create named, color-coded folders, add anchors by hash, file, or from your wallet, reorder and annotate items, then verify all, generate a report, export, or share a collection as a link others can verify and import. Stored entirely in the browser. - Flexible tagging system at
/tags: add multiple tags to any anchor and filter by tag across history, the feed, and search, with auto-suggestions from template labels, a usage-scaled tag cloud, per-tag stats, and rename, merge, recolor, and delete. Tags travel with collection exports and are stored entirely in the browser. - Interactive onboarding tour and command palette (Ctrl+K): a guided seventeen-step walkthrough that introduces the main features to first-time visitors and can be restarted any time, plus a keyboard-first command palette to jump to any page or run a common action with fuzzy search.
- On-chain contract explorer at
/explorerwith interactive read-only function calls: browse every contract's functions, maps, and data variables, watch recent on-chain calls, read an architecture diagram of how the five contracts relate, and call read-only functions directly from the UI. Exposed as JSON at/api/explorer/<contract>. - Built-in performance monitoring with Web Vitals and API metrics at
/performance: a client-side dashboard tracking Core Web Vitals (LCP, INP, CLS, FCP, TTFB, FID) with ratings and sparklines, per-page load and render times, and per-endpoint API response times, error rates, and cache hits, plus an optional debug overlay. Captured with the browser's Performance APIs and stored entirely on the device, no external analytics. - Compliance-grade audit trail with integrity verification and exportable reports at
/audit: every interaction is recorded in a tamper-evident, browser-local log with a re-verifiable SHA-256 integrity hash, filterable and paginated, with signed-style audit reports exportable as JSON, CSV, or printable HTML for academic and legal chain-of-custody. Stored entirely on the device. - Public status page with uptime monitoring and incident tracking at
/status: live health of all five contracts, the API endpoints, and the Hiro and Stacks dependencies, with response times, 24-hour uptime bars, and automatic plus manual incident reporting, exposed as JSON at/api/statusand as an embeddable status badge at/api/status/badge. - Calendar view with GitHub-style contribution graph and streak tracking at
/calendar: your anchoring activity mapped to dates, with a year contribution graph, a monthly calendar, current and longest streaks, per-day anchor detail, and per-day report generation, plus a compact graph on the dashboard and on public wallet profiles. Built from your on-chain history. - RSS/Atom/JSON feeds and webhook subscriptions for protocol events: standards-based feeds at
/api/feed/rss,/api/feed/atom, and/api/feed/json(filterable by?contract,?address, and?limit, with autodiscovery links in the page head), plus a webhook subscription manager and tester in the developer portal with a signed (HMAC-SHA256) JSON payload format for Slack, Zapier, CI, and monitoring integrations. - Full data portability with backup, restore, and privacy controls at
/settings: export everything stored in your browser (collections, tags, watchlist, audit log, notifications, preferences, and more) to a single timestamped JSON file, restore it on another device with merge or replace and an import preview, see a color-coded per-category storage breakdown, clear data individually or all at once, and centralize theme, language, notification, live update, and data-retention settings in one place. Stored entirely on the device. - Share verification results via social media and QR codes: a compact row of share buttons (copy link, X, LinkedIn, Telegram) on verification pages, wallet profiles, group pages, and the stats page, plus an expandable, in-browser-generated QR code on verification pages that encodes the verification URL so anyone can scan and verify from their phone. No external library or image service.
- Consistent copy interactions across the app: a standardized copy button (clipboard icon with a "Copied!" confirmation) plus shared truncated-hash and truncated-address components with hover-to-reveal full values, click-to-copy, and profile links, and a global toast that confirms every copy. Applied everywhere from verification pages and feeds to the developer portal.
- Polished loading states: every page that fetches data shows a skeleton loader shaped like its final layout (anchor lists, stats cards, feed and search rows, the verify record, groups, the activity timeline, and the calendar grid) with a theme-aware shimmer that respects reduced-motion, instead of spinners or blank screens.
- Wayfinding navigation across the app's 20-plus pages: an auto-generated breadcrumb trail below the nav on every page, a context-aware back button on nested pages that names the page you came from, and a recently visited menu (the clock icon in the corner) listing the last pages from this session with relative times. Navigation history stays in the browser tab and is never sent anywhere.
- Guided empty states for new users: every page that can start out empty (anchors, feed, groups, search, dashboard, activity, watchlist, collections, calendar, notifications, the audit trail, and developer API keys) shows an icon, a short explanation of what belongs there, and a clear call to action, so a brand-new wallet always has an obvious next step instead of a blank "No data" screen.
- Safe destructive actions: deletions, revocations, and data-clearing all ask first through a single confirmation dialog with danger, warning, and info variants. The most irreversible actions (Clear All Data, deleting a collection) require typing a word like DELETE to enable the confirm button, and the anchor and report pages warn before you navigate away from staged but unsaved work.
- Polished motion: page sections fade in on load, lists reveal their rows in a staggered sequence, headline stats count up as they scroll into view, and buttons, cards, and nav links carry subtle micro-interactions. All of it is plain CSS with no animation library, and every effect respects the reduced-motion setting.
- Favorites for quick access to frequently used items: star any hash, wallet, group, or page and reach it again from a collapsible favorites bar at the top of every page, a nav star with a count badge, and a dedicated favorites page grouped by type. Stored only in this browser.
- File preview with thumbnails and hash matching for integrity checks: dropping a file shows its name, size, type, modified date, and an image thumbnail or PDF page count, alongside the computed hash. A hash matcher compares a file against an anchored hash (or two files against each other) with a character-level diff, and the verify page lets you drop a file to confirm it matches the anchored hash. All hashing is client-side.
- A consistent footer on every page with organized link sections (Product, Protocol, Developers, Account), social and feed links, a live protocol stats line, a system status indicator, and a back-to-top button. Plain-language Terms of Service and Privacy Policy pages spell out the MIT license, the permanence of on-chain anchors, and that no data is collected (everything stays in your browser).
- Standardized input validation across every form: hashes, Stacks addresses, labels, and names validate as you type with a character counter, a clear error message, and a green checkmark once a value is valid. Hash and address fields auto-format pasted values (stripping whitespace and a leading
0x, lowercasing, and detecting which kind a paste is), submit buttons stay disabled until the required fields pass, and the same rules guard the REST API, which answers malformed input with a400and a specific message instead of failing deeper in. - Complete SEO and social-sharing metadata on every page: a per-page title, description, canonical URL, and Open Graph and Twitter card tags, with site-wide defaults and explicit indexing directives in the root layout. A generated
sitemap.xmllists every page (including all documentation guides, kept in sync with the docs index) with per-section change frequencies and priorities,robots.txtallows crawling while disallowing the/api/routes, and JSON-LD structured data (Organization on the landing page, WebPage on verification pages, TechArticle on the docs) makes the content machine-readable for search engines. - Comprehensive error pages that guide users back: a branded global 404 with an inline hash search and suggested links, custom not-found pages for invalid hashes, wallet addresses, and groups (validated on the server so bad links get a specific message), route-level error boundaries with a retry on every page that reads on-chain data, an auto-retrying rate-limit view, plus offline and maintenance pages. A reusable
ErrorPagecomponent keeps them consistent in light and dark themes. - Real-time event sync from chain to a Supabase index: a hosted Hiro Chainhook posts every
anchor-createdevent to/api/chainhooks, which verifies a bearer token and mirrors the events into athesis_lockstable, reorg-aware (apply and rollback) and idempotent per transaction id. Reads still work without it; the chain stays the source of truth. Seechainhooks/README.md.
Five Clarity 3 contracts deployed to Stacks mainnet at the same principal, SP3QS6X01XKTYC84BHA0J567CZTAH67BJHN88FNVM:
| Contract | Purpose |
|---|---|
thesislock |
Original single-hash anchor. One immutable record per hash. |
thesislock-batch |
Anchors up to ten hashes per transaction, keyed by { hash, owner }. |
thesislock-registry |
Per-principal append-only index of anchors. Powers "My Anchors". |
thesislock-proof |
SIP-009 NFT issuing soulbound proof tokens. |
thesislock-groups |
Named groups for collaborative anchoring under a shared history. |
The original thesislock contract was first deployed at Stacks block 7798720, burn block 947300 (deploy transaction).
- Clarity 3 smart contracts on Stacks mainnet
- Clarinet for project structure, testing, and deployment
- Next.js 16 App Router with TypeScript and Tailwind
- Stacks Connect for wallet integration (Leather, Xverse, Asigna)
- Hiro Stacks API for read-only contract calls
- Supabase as an optional real-time index of anchor events, populated by a Hiro Chainhook
- Vercel for hosting
# Contracts
npm install
clarinet check
npm test
# Frontend
cd web
npm install
cp .env.example .env.local
npm run dev # start the dev server
npm test # run the unit, component, and API tests (Vitest)The frontend lib/ utilities are covered by a Vitest unit suite in
web/lib/__tests__/, the shared React components by a React Testing Library
suite in web/app/components/__tests__/, and the public API endpoints by a
handler-level integration suite in web/app/api/__tests__/ (each route invoked
directly with its Hiro calls mocked). All run in CI alongside the build, type
check, and Playwright end-to-end tests.
Contract tests run with the Clarinet SDK and Vitest from the repo root
(npm test): 177 tests across 17 files covering the 5 Clarity contracts.
Beyond the original happy-path suites (tests/thesislock*.test.ts), the expanded
coverage adds, in tests/:
- Per-contract edge cases (
thesislock-*-edge.test.ts): empty and 64-character labels, the 65-character and 11-entry type boundaries, duplicate hashes, the registry's 10-item recent window, soulbound transfers, and group admin and membership gating. cross-contract.test.ts: anchor, register, mint, and group flows that read back consistently across contracts.boundary-values.test.ts: all-zero and all-ff hashes, punctuation, space, and pipe labels, and a maximum 128-bit uint index.concurrent-users.test.ts: independent per-principal records and counts.event-emissions.test.ts: the exact print-event tuple for every public call.error-codes.test.ts: a documented sweep of u100, u400, u401, u403, and u409.read-only-functions.test.tsandgas-estimation.test.ts: every read-only function, plus informational per-call cost logging (run with-- --costs).
The contract suite runs in the Contracts CI job (clarinet check then
npm test), which discovers every file under tests/. The frontend Vitest and
Playwright suites under web/ are described above. All suites run on every push.
ESLint, Prettier, and strict TypeScript keep the web app, SDK, and CLI consistent. Each package exposes the same scripts:
cd web # or sdk, or cli
npm run lint # ESLint
npm run format # apply Prettier
npm run format:check # verify formattingThe web app additionally runs npx tsc --noEmit for type checking. A husky
pre-commit hook runs lint-staged so staged files are linted and formatted before
each commit, and CI runs lint and format checks for every package. See
CODESTYLE.md for the full conventions.
Security practices and the vulnerability-reporting process are documented in SECURITY.md. In summary:
- Documents are hashed with SHA-256 in the browser and never uploaded. The chain is the source of truth and reads go through the public Hiro API.
- Every response carries a strict Content-Security-Policy and hardening headers,
built in
web/proxy.tsandweb/lib/csp.ts. Embeddable badge and image routes opt into cross-origin loading; every other route denies framing. - User input is sanitized before it reaches a contract call, the Hiro API, a CSV
export, or the DOM (
web/lib/sanitize.ts), the client rate-limits its own API calls (web/lib/rateLimit.ts), and public configuration is validated on load (web/lib/env.ts). - Dependencies are audited in CI and the build fails on any high or critical advisory. Run the same checks locally:
cd web # or the repo root, sdk, or cli
npm audit --audit-level=high
npm run audit:sri # web only: confirms no unpinned third-party subresourcesTo report a vulnerability, use GitHub's private "Report a vulnerability" flow as described in SECURITY.md. Please do not open a public issue for a sensitive report.
In-app help lives at thesis-lock.vercel.app/help: a
searchable FAQ, step-by-step
guides,
troubleshooting, and a
contact page. Contextual help links across the
app deep-link into the relevant topic, and the command palette surfaces FAQ answers as you
type. All help content is defined in one place, web/lib/help.ts.
Release notes and the full version history live at
thesis-lock.vercel.app/changelog, with a
release RSS feed you can follow in a feed reader,
and returning visitors see a what's-new summary after each update. The current version is
v1.6.0; the version and release history are defined in web/lib/version.ts, and the deployed
version is also available from GET /api/version.
Full guides and reference live at thesis-lock.vercel.app/docs:
- Getting Started: what ThesisLock is and how to anchor your first document.
- Getting Started Tour: the interactive onboarding tour, what it covers, and how to restart it.
- Command Palette: the Ctrl+K command palette for jumping to any page or running a common action.
- Navigation: breadcrumbs, the context-aware back button, and the recently visited pages menu.
- Empty States: the guided empty states that explain what belongs on each page and point to the next step.
- Confirmation Dialogs: how destructive actions ask first, the dialog variants, and the useConfirm hook.
- Animations: the fade-in, stagger, and count-up components, the micro-interactions, and reduced-motion support.
- Contracts: all five contracts, function signatures, and direct Hiro API calls.
- Contract Explorer: browse contracts in the app with recent calls, an architecture diagram, and an interactive read-only tester.
- Watchlist: monitor specific hashes, wallets, and groups and track their status over time.
- Collections: organize anchored documents into named, browser-local collections and share them as links.
- Favorites: star hashes, wallets, groups, and pages for quick access from the favorites bar and page.
- Hash Matching: file previews with thumbnails, and the hash matcher for confirming a file matches an anchored hash.
- Web App Guide: anchoring, batches, groups, verification, and proof NFTs.
- API Reference: the JSON REST API for verification, search, stats, badges, and cards.
- SDK Guide: the
thesislock-sdkTypeScript package (sdk/, changelog). - CLI Guide: the
thesislock-cliterminal tool withverify,hash,status,search, andbatchcommands, plus--json/--quietoutput and shell completions (cli/, changelog). - GitHub Action: gate a CI pipeline on an on-chain anchor (
action/). - System Status: the public status page, what it monitors, and the status JSON API and badge.
- Feeds: RSS, Atom, and JSON Feed endpoints for protocol events, with filtering and autodiscovery.
- Webhooks: event types, the signed JSON payload format, and signature verification.