chore: scaffold PYRE MVP monorepo (structure + docs)

pnpm + TypeScript workspace per design doc §13:
- apps/{web,api,worker} skeletons (Next.js 16, Fastify 5, BullMQ)
- packages/{core,solana,prometheus,db,config} (core has real types/DTOs;
  solana/prometheus are stubs)
- programs/pyre-core placeholder (future Anchor, v1.0)
- docs/: PYRE_MVP_DESIGN (canonical), ARCHITECTURE, SECURITY, TOKEN_CLASSIFICATION
- CLAUDE.md, README, .env.example (no private-key var by design)

Skeleton + docs only — no Solana/business logic yet. All workspaces typecheck clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-31 02:20:55 +00:00
parent e86b57e00f
commit c20094ab56
65 changed files with 13834 additions and 1 deletions

49
.env.example Normal file
View File

@@ -0,0 +1,49 @@
# ============================================================================
# PYRE / Prometheus Protocol — environment template
# Copy to .env (per app) and fill in. NEVER commit a real .env.
#
# CORE TRUST RULE: PYRE never holds private keys. There is intentionally NO
# wallet private key / mnemonic variable anywhere in this file. All signing
# happens client-side in the user's wallet.
# ============================================================================
# ---- Solana ----------------------------------------------------------------
# Use an external RPC provider (Helius, Triton, QuickNode, etc.).
# Do NOT run a validator/RPC node on the MVP VPS.
SOLANA_RPC_URL=https://api.mainnet-beta.solana.com
SOLANA_RPC_WS_URL=
SOLANA_CLUSTER=mainnet-beta # mainnet-beta | devnet | testnet
# ---- Database (PostgreSQL) -------------------------------------------------
DATABASE_URL=postgresql://pyre:pyre@localhost:5432/pyre
# ---- Redis (queues, cache, rate limiting) ----------------------------------
REDIS_URL=redis://localhost:6379
# ---- AI services (Prometheus) ----------------------------------------------
# API-based only for MVP. Do NOT run local LLMs/image models on the server.
ANTHROPIC_API_KEY=
OPENAI_API_KEY=
IMAGE_GEN_PROVIDER= # e.g. openai | stability | replicate
IMAGE_GEN_API_KEY=
# ---- App URLs / ports ------------------------------------------------------
WEB_PORT=3000
API_PORT=4000
WEB_PUBLIC_URL=http://localhost:3000
API_PUBLIC_URL=http://localhost:4000
# ---- Admin / security ------------------------------------------------------
ADMIN_API_TOKEN= # protects /admin endpoints
RATE_LIMIT_SCAN_PER_MIN=10
# ---- Classification safety thresholds --------------------------------------
PROTECTED_USD_THRESHOLD=50 # skip tokens valued above this (USD)
MAX_PRICE_IMPACT_BPS=300 # skip swap routes above this impact
QUOTE_MAX_AGE_MS=15000 # skip stale quotes older than this
# ---- Optional: metadata / launch (later phases) ----------------------------
IPFS_OR_ARWEAVE_ENDPOINT=
IPFS_OR_ARWEAVE_TOKEN=
# Public key only — the operator signs Pump.fun launches manually in MVP.
PUMPFUN_CREATOR_WALLET_PUBKEY=

38
.gitignore vendored Normal file
View File

@@ -0,0 +1,38 @@
# dependencies
node_modules/
.pnpm-store/
# builds
dist/
build/
.next/
out/
*.tsbuildinfo
# rust / anchor (programs/pyre-core, later)
target/
.anchor/
# env & secrets — NEVER commit
.env
.env.*
!.env.example
# logs
*.log
logs/
npm-debug.log*
pnpm-debug.log*
# test / coverage
coverage/
.vitest/
# editor / os
.DS_Store
.idea/
.vscode/*
!.vscode/extensions.json
# serena (keep project memories, ignore local cache)
.serena/cache/

5
.npmrc Normal file
View File

@@ -0,0 +1,5 @@
# pnpm settings
engine-strict=true
# keep dependency boundaries explicit across the workspace
shamefully-hoist=false
auto-install-peers=true

2
.serena/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/cache
/project.local.yml

View File

@@ -0,0 +1,23 @@
# Repo structure (pnpm + TypeScript monorepo)
Root: `/home/pyre/pyre`. pnpm workspaces (`apps/*`, `packages/*`). All packages: `@pyre/<name>`, ESM (`"type":"module"`), tsconfig extends `tsconfig.base.json` (strict, Bundler resolution, verbatimModuleSyntax → use `.js` extensions on relative imports).
## apps/ (runtime services)
- `apps/web` (@pyre/web) — Next.js 15 + React 19 + Tailwind + Solana Wallet Adapter. Landing, wallet connect, scanner UI, cleanup preview, receipt page, Prometheus preview, admin review.
- `apps/api` (@pyre/api) — Fastify 5. Endpoints (§14): POST /api/scan, /api/build/close-empty, /api/build/burn, /api/receipt, /api/prometheus/generate, + admin. Has /health live.
- `apps/worker` (@pyre/worker) — BullMQ jobs: metadata enrichment, AI generation, image prompts, safety checks, collision checks, confirmation tracking, receipt enrichment.
## packages/ (shared libs)
- `packages/core` (@pyre/core) — **real type defs**: `TokenClassification` enum (EMPTY_CLOSE_ONLY, INCINERATE_ONLY, TRANSMUTABLE, PROTECTED_SKIP, UNSUPPORTED), API DTOs, CleanupReceipt, Prometheus I/O, risk types. Lamports as strings.
- `packages/solana` (@pyre/solana) — STUBS only (throw "not implemented"): parseTokenAccounts, buildCloseEmptyAccountsTx, buildBurnTx, simulateTransaction, decodeTransaction. deps @solana/web3.js, @solana/spl-token.
- `packages/prometheus` (@pyre/prometheus) — STUBS: buildPrompt, runMetaMixer, parseOutput, runSafetyChecks, generateImagePrompt.
- `packages/db` (@pyre/db) — table-name constants + createPool() stub (pg). Tables in §15.
- `packages/config` (@pyre/config) — Env interface + loadConfig() stub mapping `.env.example`. No private-key var by design.
## other
- `programs/pyre-core` — future Anchor program (v1.0, placeholder README).
- `docs/` — PYRE_MVP_DESIGN.md (canonical), ARCHITECTURE.md, SECURITY.md, TOKEN_CLASSIFICATION.md.
- `preview.html`, `scripts/`, `infra/`, `CLAUDE.md`, `.env.example`.
## CURRENT STATE
Scaffold + docs only. NO Solana/business logic implemented (intentional). `pnpm install` has NOT been run. Dependency version ranges were set from model knowledge — verify against registry/context7 before relying on exact majors.

View File

@@ -0,0 +1,21 @@
# PYRE / Prometheus Protocol
Solana wallet-cleanup + ritual meme-rebirth protocol. Tagline: "Burn the dead. Feed the PYRE. Claim the Spawn."
## What it does
Users connect a Solana wallet; PYRE scans SPL token accounts, classifies them, and helps the user safely close empty associated token accounts (ATAs) and burn junk — **returning reclaimed ATA rent to the user**. A later AI layer ("Prometheus") generates a new meme-token identity ("Spawn") from burned/transmuted remnants, launched semi-manually via Pump.fun.
## MVP scope (build order)
- **v0.1 Burner/Cleaner** (current focus): wallet connect → scan → classify → close empty ATAs → optional burn → return rent → receipt.
- v0.2 Prometheus Meta Mixer (AI generation, human-reviewed) · v0.3 Manual Pump.fun workflow · v0.4 Essence ledger (off-chain) · v1.0 PYRE Core Anchor program.
## NON-NEGOTIABLE trust rules
- PYRE **never holds private keys**; never custodial signing; never auto-execute.
- Recovered ATA rent **returns to the user by default** (never silently taxed/pooled).
- Always **show + decode + match** a transaction preview before the user signs.
- Classifier is conservative: **"Unknown means skip."** Never say "this token is safe" — say "appears eligible based on current checks."
## Out of scope for v0.1
Auto Pump.fun launch, Essence vault, custom Solana program, Token-2022, NFTs, automatic valuable-token sacrifice, custodial signing, background automation.
Canonical spec: `docs/PYRE_MVP_DESIGN.md` (source of truth). See also `docs/SECURITY.md`, `docs/TOKEN_CLASSIFICATION.md`, `docs/ARCHITECTURE.md`, `CLAUDE.md`.

View File

@@ -0,0 +1,23 @@
# Commands & conventions
## Toolchain (Linux, no sudo)
- Node 22, `pnpm` 11.5.0 installed standalone at `~/.local/share/pnpm/bin` (added to ~/.bashrc PATH; new shells get it). If `pnpm` not found, use `~/.local/share/pnpm/bin/pnpm` or `source ~/.bashrc`.
- `uv`/`uvx` at `~/.local/bin` (used by the Serena MCP server).
## Workspace commands (from repo root)
- `pnpm install` — install all workspace deps (NOT yet run; expect first-run version fixups).
- `pnpm -r build` · `pnpm -r typecheck` · `pnpm -r test` · `pnpm dev` (parallel dev).
- Per package: `pnpm --filter @pyre/api dev`, etc.
- `lint`/`test` are placeholder echo scripts for now.
## Conventions
- TypeScript strict; ESM only. Because base tsconfig uses `verbatimModuleSyntax` + `moduleResolution: Bundler`, relative imports need explicit `.js` extensions.
- Internal deps via `workspace:*`. Package names `@pyre/<name>`.
- Lamport/SOL amounts passed as **strings** in DTOs.
- Server must **recompute classification**; never trust client-submitted classifications.
- Secrets only via env (`.env`, never committed). There is intentionally **no private-key/mnemonic env var**.
## First Claude Code prompts (from §20)
1. Plan-only: "Read CLAUDE.md and docs/PYRE_MVP_DESIGN.md. Do not write code yet. Produce an implementation plan for PYRE MVP v0.1 ..."
2. Then skeleton (already done): monorepo with pnpm workspaces.
Next real work = Phase 1 (Wallet Scanner): implement scan endpoint + classification in @pyre/core/@pyre/solana, wallet-connect UI.

133
.serena/project.yml Normal file
View File

@@ -0,0 +1,133 @@
# the name by which the project can be referenced within Serena
project_name: "pyre"
# list of languages for which language servers are started; choose from:
# al angular ansible bash clojure
# cpp cpp_ccls crystal csharp csharp_omnisharp
# dart elixir elm erlang fortran
# fsharp go groovy haskell haxe
# hlsl html java json julia
# kotlin lean4 lua luau markdown
# matlab msl nix ocaml pascal
# perl php php_phpactor powershell python
# python_jedi python_ty r rego ruby
# ruby_solargraph rust scala scss solidity
# svelte swift systemverilog terraform toml
# typescript typescript_vts vue yaml zig
# (This list may be outdated. For the current list, see values of Language enum here:
# https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py
# For some languages, there are alternative language servers, e.g. csharp_omnisharp, ruby_solargraph.)
# Note:
# - For C, use cpp
# - For JavaScript, use typescript
# - For Angular projects, use angular (subsumes typescript+html; requires `npm install` in the project root)
# - For Svelte projects, use svelte (subsumes typescript/javascript for .svelte projects; requires npm)
# - For SCSS / Sass / plain CSS, use scss (some-sass-language-server handles all three)
# - For Free Pascal/Lazarus, use pascal
# Special requirements:
# Some languages require additional setup/installations.
# See here for details: https://oraios.github.io/serena/01-about/020_programming-languages.html#language-servers
# When using multiple languages, the first language server that supports a given file will be used for that file.
# The first language is the default language and the respective language server will be used as a fallback.
# Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored.
languages:
- typescript
# the encoding used by text files in the project
# For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings
encoding: "utf-8"
# line ending convention to use when writing source files.
# Possible values: unset (use global setting), "lf", "crlf", or "native" (platform default)
# This does not affect Serena's own files (e.g. memories and configuration files), which always use native line endings.
line_ending:
# The language backend to use for this project.
# If not set, the global setting from serena_config.yml is used.
# Valid values: LSP, JetBrains
# Note: the backend is fixed at startup. If a project with a different backend
# is activated post-init, an error will be returned.
language_backend:
# whether to use project's .gitignore files to ignore files
ignore_all_files_in_gitignore: true
# advanced configuration option allowing to configure language server-specific options.
# Maps the language key to the options.
# Have a look at the docstring of the constructors of the LS implementations within solidlsp (e.g., for C# or PHP) to see which options are available.
# No documentation on options means no options are available.
ls_specific_settings: {}
# list of additional workspace folder paths for cross-package reference support (e.g. in monorepos).
# Paths can be absolute or relative to the project root.
# Each folder is registered as an LSP workspace folder, enabling language servers to discover
# symbols and references across package boundaries.
# Currently supported for: TypeScript.
# Example:
# additional_workspace_folders:
# - ../sibling-package
# - ../shared-lib
additional_workspace_folders: []
# list of additional paths to ignore in this project.
# Same syntax as gitignore, so you can use * and **.
# Note: global ignored_paths from serena_config.yml are also applied additively.
ignored_paths: []
# whether the project is in read-only mode
# If set to true, all editing tools will be disabled and attempts to use them will result in an error
# Added on 2025-04-18
read_only: false
# list of tool names to exclude.
# This extends the existing exclusions (e.g. from the global configuration)
# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html
excluded_tools: []
# list of tools to include that would otherwise be disabled (particularly optional tools that are disabled by default).
# This extends the existing inclusions (e.g. from the global configuration).
# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html
included_optional_tools: []
# fixed set of tools to use as the base tool set (if non-empty), replacing Serena's default set of tools.
# This cannot be combined with non-empty excluded_tools or included_optional_tools.
# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html
fixed_tools: []
# list of mode names that are to be activated by default, overriding the setting in the global configuration.
# The full set of modes to be activated is base_modes (from global config) + default_modes + added_modes.
# If the setting is undefined/empty, the default_modes from the global configuration (serena_config.yml) apply.
# Otherwise, this overrides the setting from the global configuration (serena_config.yml).
# Therefore, you can set this to [] if you do not want the default modes defined in the global config to apply
# for this project.
# This setting can, in turn, be overridden by CLI parameters (--mode).
# See https://oraios.github.io/serena/02-usage/050_configuration.html#modes
default_modes:
# list of mode names to be activated additionally for this project, e.g. ["query-projects"]
# The full set of modes to be activated is base_modes (from global config) + default_modes + added_modes.
# See https://oraios.github.io/serena/02-usage/050_configuration.html#modes
added_modes:
# initial prompt for the project. It will always be given to the LLM upon activating the project
# (contrary to the memories, which are loaded on demand).
initial_prompt: ""
# time budget (seconds) per tool call for the retrieval of additional symbol information
# such as docstrings or parameter information.
# This overrides the corresponding setting in the global configuration; see the documentation there.
# If null or missing, use the setting from the global configuration.
symbol_info_budget:
# list of regex patterns which, when matched, mark a memory entry as readonly.
# Extends the list from the global configuration, merging the two lists.
read_only_memory_patterns: []
# list of regex patterns for memories to completely ignore.
# Matching memories will not appear in list_memories or activate_project output
# and cannot be accessed via read_memory or write_memory.
# To access ignored memory files, use the read_file tool on the raw file path.
# Extends the list from the global configuration, merging the two lists.
# Example: ["_archive/.*", "_episodes/.*"]
ignored_memory_patterns: []

164
CLAUDE.md Normal file
View File

@@ -0,0 +1,164 @@
# CLAUDE.md — PYRE / Prometheus Protocol
Operating guide for Claude Code sessions in this repo. Keep changes aligned with
the canonical design at [`docs/PYRE_MVP_DESIGN.md`](docs/PYRE_MVP_DESIGN.md) —
when in doubt, that document wins.
PYRE is a Solana wallet-cleanup and ritual meme-rebirth protocol. Users connect a
wallet; PYRE scans SPL token accounts, classifies them conservatively, and helps
the user safely close empty associated token accounts (ATAs) and burn obvious
junk — returning recovered rent to the user and producing a clear receipt. A
later layer (Prometheus) uses API-based AI to generate a meme-token "Spawn" from
burned remnants for manual, human-reviewed launch.
> **Burn the dead. Feed the PYRE. Claim the Spawn.**
---
## Non-negotiable trust rules
These are load-bearing. Do not weaken, work around, or "optimize" them. See
§3, §7, and §16 of the design doc.
- **PYRE never holds private keys.** There is no key/mnemonic env var and there
never will be. All signing happens client-side in the user's wallet.
- **No custodial signing, ever.** Never auto-execute a transaction without the
user signing it locally in their wallet.
- **Recovered ATA rent returns to the user by default.** Rent must not be
silently taxed, redirected, pooled, or counted as Essence. (Donation modes, if
ever added, must be explicit opt-in.)
- **Always preview before signing.** Build the unsigned transaction, **decode**
it, and **match** the decoded contents against the preview shown to the user
(accounts to close, tokens to burn, rent amount, rent destination, fees,
warnings) before any signature is requested. Simulate transactions first.
- **Unknown means skip.** Anything the system cannot safely reason about defaults
to `PROTECTED_SKIP` / `UNSUPPORTED`. The user must manually opt in to anything
risky.
- **Never claim a token is safe.** The classifier must never say "this token is
safe." It may only say "this token **appears eligible** based on current
checks."
---
## Current status & scope guardrail
**MVP v0.1 is a burner/cleaner only.** This repo is currently **scaffold + docs**:
**Solana transaction logic and business logic are NOT yet implemented.** Do not
add application/business logic unless explicitly asked.
**Explicitly OUT of scope for v0.1** (per §5):
- Automatic Pump.fun launch
- User-contributed Essence vault
- Custom PYRE Solana program (Anchor)
- Token-2022 support
- NFT handling (incl. compressed NFTs)
- Automatic valuable-token sacrifice
- Custodial signing
- Background wallet automation
v0.1 ships: wallet connect → scan token accounts → classify → close eligible
empty ATAs (optionally burn obvious junk) → return rent to user → show receipt.
---
## Repo layout
```
pyre/
apps/
web/ # Next.js user app: landing, wallet connect, scanner UI,
# cleanup preview, receipt page, Prometheus preview, admin review
api/ # Fastify HTTP API: scan, classify, build tx, receipt,
# generation, admin endpoints
worker/ # BullMQ worker: async metadata lookup, AI generation,
# safety checks, tx-confirmation watcher, receipt enrichment
packages/
core/ # shared types & logic: classification enums, risk rules,
# DTOs, receipt schema, Prometheus I/O schema
solana/ # Solana tx helpers: token-account parsing, close-account &
# burn tx builders, simulation helpers, tx decoder
prometheus/ # AI generation: prompt templates, meta mixer, output parser,
# safety checks, image-prompt generator
db/ # database schema, migrations, table definitions
config/ # shared config & environment loading
programs/
pyre-core/ # FUTURE Anchor program (v1.0). NOT needed for the burner MVP.
docs/ # design + architecture + security + classification docs
scripts/
infra/
```
See §13 for full responsibilities.
---
## Tech stack
- **web** — Next.js, TypeScript, Tailwind, Solana Wallet Adapter, React Query or
Zustand.
- **api** — Node.js, Fastify, TypeScript, PostgreSQL, Redis, BullMQ.
- **worker** — Node.js worker process, BullMQ, Redis, AI API clients.
- **Database** — PostgreSQL.
- **Solana RPC** — external provider only (Helius/Triton/QuickNode/etc.). Do
**not** run a validator or RPC node on the MVP VPS.
- **AI** — API-based only (text + image + moderation). Do **not** run local LLMs
or image models on the server.
---
## Dev commands
`pnpm` is installed at `~/.local/share/pnpm/bin` — if `pnpm` is not found, add
that to `PATH` (e.g. `export PATH="$HOME/.local/share/pnpm/bin:$PATH"`).
Node 22 is required.
```bash
pnpm install # install workspace deps
pnpm -r build # build all packages/apps
pnpm -r typecheck # type-check all
pnpm -r test # run all tests
pnpm dev # run apps in parallel (dev)
```
> **Nothing is installed yet.** These commands are not runnable until the
> skeleton's `package.json` files and dependencies exist.
---
## Conventions
- **TypeScript strict** — every package extends `tsconfig.base.json`.
- **ESM** — `"type": "module"` throughout.
- **Workspace deps** — reference internal packages via `workspace:*`.
- **Package names** — `@pyre/<name>` (e.g. `@pyre/core`, `@pyre/solana`).
---
## Docs
- [`docs/PYRE_MVP_DESIGN.md`](docs/PYRE_MVP_DESIGN.md) — canonical design (source of truth)
- [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) — system architecture
- [`docs/SECURITY.md`](docs/SECURITY.md) — security requirements
- [`docs/TOKEN_CLASSIFICATION.md`](docs/TOKEN_CLASSIFICATION.md) — classification rules
(Sibling docs are being authored in parallel.)
---
## Bootstrap prompts (§20)
Use these in order. **Plan first — no code:**
> Read CLAUDE.md and docs/PYRE_MVP_DESIGN.md. Do not write code yet. Produce an
> implementation plan for PYRE MVP v0.1 focused only on wallet scanning, token
> account classification, close-empty-ATA transaction building, transaction
> preview, and receipt generation. Identify the exact packages, APIs, database
> tables, and test cases needed.
Then, after plan review — **skeleton only:**
> Create the monorepo skeleton with pnpm workspaces. Add apps/web, apps/api,
> apps/worker, packages/core, packages/solana, packages/prometheus, packages/db,
> and docs. Add TypeScript configs, package.json files, README files, and
> .env.example files. Do not implement Solana transaction logic yet.

View File

@@ -1,2 +1,92 @@
# pyre # PYRE / Prometheus Protocol
> **Burn the dead. Feed the PYRE. Claim the Spawn.**
PYRE is a **Solana wallet-cleanup and ritual meme-rebirth protocol**. You connect
a wallet; PYRE scans your SPL token accounts, classifies them conservatively, and
helps you safely close empty associated token accounts (ATAs) and burn obvious
junk — **returning recovered rent to you** and producing a clear, shareable
receipt. A later layer (Prometheus) uses AI to generate a meme-token "Spawn" from
burned remnants for **manual, human-reviewed** launch.
The first emotional win is simple: *"PYRE cleaned my wallet and returned SOL I
forgot was trapped in token accounts."*
## What PYRE is — and is not
PYRE **is**: wallet cleanup, token-scrap transmutation, recovered-rent return,
transparent contribution accounting, AI-generated meme rebirth, and ritual
entertainment.
PYRE is **NOT** an investment product, yield mechanism, trading bot,
guaranteed-profit system, or protected launch mechanism. It makes no profit
promises.
**Trust guarantees:** PYRE never holds your private keys, never signs
custodially, and always shows a decoded transaction preview that matches what you
sign. Recovered rent goes back to your wallet by default. Anything the system
cannot safely reason about is skipped.
## The burner flow at a glance
```
Connect wallet
→ scan token accounts
→ classify accounts (closeable / burnable / transmutable / protected / unsupported)
→ preview the transaction (accounts, rent, destination, fees, warnings)
→ you sign locally in your wallet
→ recovered rent returns to you
→ see your PYRE receipt
```
## Roadmap
- **v0.1 — Burner / Cleaner** *(current focus)*: wallet connect, scan, classify,
close empty ATAs, optional junk burn, rent return, receipt.
- **v0.2 — Prometheus Meta Mixer**: AI generation of a Spawn identity from
burned/cleaned token context (candidate package only — no auto-launch).
- **v0.3 — Manual Pump.fun Workflow**: human reviews the Spawn package and
manually creates the token; PYRE records mint, URL, metadata, and tx.
- **v0.4 — Essence Ledger**: record net SOL value of safe scrap swaps as Essence
per wallet/round (database-only, experimental, no claim promises).
- **v1.0 — PYRE Core Program**: custom Solana (Anchor) program for trust-critical
accounting — rounds, Essence vault, contribution receipts, Spawn distribution,
claims, and refunds.
## Repo structure
```
apps/
web/ Next.js user app (wallet connect, scanner, preview, receipt)
api/ Fastify HTTP API (scan, classify, build tx, receipt, generation)
worker/ BullMQ background worker (metadata, AI, safety, confirmations)
packages/
core/ shared types, classification enums, risk rules, schemas
solana/ token-account parsing, close/burn tx builders, decoder, simulation
prometheus/ AI prompt templates, meta mixer, output parser, safety checks
db/ database schema and migrations
config/ shared config & env loading
programs/
pyre-core/ future Anchor program (v1.0)
docs/ design, architecture, security, classification
```
## Quick start
> **This is a scaffold.** The commands below are not yet runnable — the workspace
> package definitions and source are still being built out.
**Prerequisites:** Node 22, pnpm, PostgreSQL, Redis.
```bash
cp .env.example .env # then fill in values (no private keys — by design)
pnpm install
pnpm dev # (once apps are implemented)
```
## Docs
See [`docs/`](docs/) — start with
[`docs/PYRE_MVP_DESIGN.md`](docs/PYRE_MVP_DESIGN.md) (the canonical design), then
[`ARCHITECTURE.md`](docs/ARCHITECTURE.md), [`SECURITY.md`](docs/SECURITY.md), and
[`TOKEN_CLASSIFICATION.md`](docs/TOKEN_CLASSIFICATION.md).

38
apps/api/README.md Normal file
View File

@@ -0,0 +1,38 @@
# @pyre/api
PYRE backend HTTP API. **Skeleton only** — endpoints exist as TODO stubs/route
placeholders, NOT real implementations. No Solana transaction or scan/build
logic is implemented yet (see [`CLAUDE.md`](../../CLAUDE.md), §14).
Stack: Node.js + Fastify + TypeScript, with PostgreSQL (`@pyre/db`), Redis +
BullMQ for queueing jobs handled by `@pyre/worker`.
## Responsibilities (§13)
Token scan coordination, classification helpers, route evaluation, AI generation
orchestration, metadata preparation, receipt storage, Spawn record storage,
public API, admin API.
## Endpoints to implement (§14) — TODO
- [ ] `POST /api/scan` — scan a wallet's token accounts; return summary + accounts.
- [ ] `POST /api/build/close-empty` — build unsigned close-account tx for empty ATAs.
- [ ] `POST /api/build/burn` — build unsigned burn tx for selected junk tokens.
- [ ] `POST /api/receipt` — record/return a cleanup receipt for a confirmed tx.
- [ ] `POST /api/prometheus/generate` — enqueue a Prometheus Spawn generation job.
- [ ] Admin endpoints — review/approve/reject generated Spawn packages.
Currently only `GET /health` is wired up.
## Backend security rules (§16)
Rate-limit scan endpoints, validate wallet pubkeys, validate token-account
ownership, never trust client-submitted classifications (recompute server-side),
log all transaction-build requests, protect admin endpoints, use env secrets only.
## Scripts
- `dev``tsx watch src/index.ts`
- `build``tsc -p tsconfig.json`
- `typecheck``tsc --noEmit`
- `lint` / `test` — placeholders for now

28
apps/api/package.json Normal file
View File

@@ -0,0 +1,28 @@
{
"name": "@pyre/api",
"version": "0.1.0",
"private": true,
"type": "module",
"description": "PYRE backend HTTP API (Fastify) — scan, classify, build transaction, receipt, generation, admin endpoints.",
"scripts": {
"build": "tsc -p tsconfig.json",
"dev": "tsx watch src/index.ts",
"typecheck": "tsc --noEmit",
"lint": "echo \"TODO: lint\"",
"test": "echo \"TODO: tests\""
},
"dependencies": {
"@pyre/config": "workspace:*",
"@pyre/core": "workspace:*",
"@pyre/db": "workspace:*",
"@pyre/solana": "workspace:*",
"bullmq": "^5.34.0",
"fastify": "^5.2.0",
"ioredis": "^5.4.2"
},
"devDependencies": {
"@types/node": "^22.10.0",
"tsx": "^4.19.2",
"typescript": "^5.7.2"
}
}

57
apps/api/src/index.ts Normal file
View File

@@ -0,0 +1,57 @@
// PYRE backend API — SKELETON ONLY.
//
// Minimal Fastify bootstrap. Only `/health` is wired up. The §14 endpoints
// below are intentionally NOT implemented — no scan/classify/build logic here.
//
// Trust rules (§16): never request private keys, never sign custodially,
// always build an unsigned tx the client decodes + previews before signing,
// validate wallet pubkeys, validate token-account ownership, never trust
// client-submitted classifications (recompute server-side), log all tx-build
// requests, rate-limit scan endpoints, protect admin endpoints.
import Fastify from "fastify";
const app = Fastify({ logger: true });
app.get("/health", async () => {
return { status: "ok", service: "@pyre/api" };
});
// TODO (§14): implement the following routes as real, validated handlers.
// POST /api/scan
// in: { wallet }
// out: { scanId, wallet, summary, accounts[] }
//
// POST /api/build/close-empty
// in: { wallet, accountAddresses[] }
// out: { transactionBase64, preview: { accountsToClose,
// estimatedRentReturnedLamports, rentDestination } }
//
// POST /api/build/burn
// in: { wallet, items[] }
// out: { transactionBase64, preview: { tokensToBurn, accountsPotentiallyClosable } }
//
// POST /api/receipt
// in: { wallet, txSignature, scanId }
// out: { receiptId, txSignature, rentReturnedLamports, closedAccounts,
// burnedTokens, skippedTokens }
//
// POST /api/prometheus/generate (enqueue BullMQ job for @pyre/worker)
// in: { receiptId, chaos, operatorSeed? }
// out: { generationId, spawnName, ticker, lore, imagePrompt, metadata, riskFlags }
//
// Admin endpoints — review/approve/reject Spawn generations (protected).
const port = Number(process.env.PORT ?? 3001);
const host = process.env.HOST ?? "0.0.0.0";
// TODO: load + validate config via @pyre/config instead of reading process.env here.
app
.listen({ port, host })
.then((address) => {
app.log.info(`@pyre/api listening on ${address}`);
})
.catch((err) => {
app.log.error(err);
process.exit(1);
});

9
apps/api/tsconfig.json Normal file
View File

@@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}

43
apps/web/README.md Normal file
View File

@@ -0,0 +1,43 @@
# @pyre/web
User-facing PYRE web app. **Skeleton only** — no wallet or business logic is
implemented yet (see [`CLAUDE.md`](../../CLAUDE.md) and §13 of the design doc).
Stack: Next.js (App Router) + TypeScript + Tailwind + Solana Wallet Adapter +
React Query.
## Responsibilities (§13)
- Landing page
- Wallet connect (Solana Wallet Adapter)
- Scanner UI — display token accounts and classification grouping
- Cleanup preview — accounts to close, tokens to burn, rent returned, fees,
warnings, rent destination (decode tx and match against preview before signing)
- Receipt page — tx signature, accounts closed, tokens burned, rent returned,
skipped accounts
- Prometheus generation preview — Spawn name/ticker/lore/image-prompt review
- Admin review page — approve/reject generated Spawn packages
## Trust rules (do not weaken)
- PYRE never holds private keys; all signing is client-side in the user's wallet.
- Always show a preview and match the decoded transaction against it before
requesting a signature.
- Recovered ATA rent returns to the user by default.
## TODO
- [ ] Tailwind + PostCSS config and global styles
- [ ] WalletAdapter / React Query providers
- [ ] Scanner page wired to `POST /api/scan`
- [ ] Cleanup preview + transaction decode/match UI
- [ ] Sign flow via wallet adapter
- [ ] Receipt page wired to `POST /api/receipt`
- [ ] Prometheus generation preview + admin review pages
## Scripts
- `dev``next dev`
- `build``next build`
- `typecheck``tsc --noEmit`
- `lint` / `test` — placeholders for now

34
apps/web/package.json Normal file
View File

@@ -0,0 +1,34 @@
{
"name": "@pyre/web",
"version": "0.1.0",
"private": true,
"type": "module",
"description": "PYRE web app — Next.js user-facing UI: landing, wallet connect, scanner, cleanup preview, receipt, Prometheus preview, admin review.",
"scripts": {
"build": "next build",
"dev": "next dev",
"typecheck": "tsc --noEmit",
"lint": "echo \"TODO: lint\"",
"test": "echo \"TODO: tests\""
},
"dependencies": {
"@pyre/core": "workspace:*",
"@solana/wallet-adapter-react": "^0.15.39",
"@solana/wallet-adapter-react-ui": "^0.9.39",
"@solana/wallet-adapter-wallets": "^0.19.38",
"@solana/web3.js": "^1.98.4",
"@tanstack/react-query": "^5.100.0",
"next": "^16.2.6",
"react": "^19.2.0",
"react-dom": "^19.2.0"
},
"devDependencies": {
"@tailwindcss/postcss": "^4.3.0",
"@types/node": "^22.10.0",
"@types/react": "^19.2.0",
"@types/react-dom": "^19.2.0",
"postcss": "^8.5.15",
"tailwindcss": "^4.3.0",
"typescript": "^5.7.2"
}
}

View File

@@ -0,0 +1,8 @@
/** Tailwind CSS v4 PostCSS setup. */
const config = {
plugins: {
"@tailwindcss/postcss": {},
},
};
export default config;

View File

@@ -0,0 +1,3 @@
@import "tailwindcss";
/* PYRE global styles. TODO: theme tokens (ember palette) once UI work begins. */

View File

@@ -0,0 +1,17 @@
import type { ReactNode } from "react";
import "./globals.css";
export const metadata = {
title: "PYRE — Burn the dead. Feed the PYRE. Claim the Spawn.",
description:
"Solana wallet cleanup: scan token accounts, close empty ATAs, and recover rent to your wallet.",
};
// Root layout (Next.js App Router). Intentionally minimal — UI is built in later phases.
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}

20
apps/web/src/app/page.tsx Normal file
View File

@@ -0,0 +1,20 @@
// PYRE landing page — SKELETON ONLY.
//
// TODO (§13): build out the real landing experience and wire up the app:
// - Wallet connect (Solana Wallet Adapter) — NO wallet logic here yet.
// - Entry point into the scanner UI (POST /api/scan).
// - Links to cleanup preview, receipt, Prometheus preview, and admin review.
//
// Trust rules: PYRE never holds private keys; signing is always client-side and
// must be preceded by a decoded-transaction preview that matches what the user
// sees. See ../../README.md and the repo CLAUDE.md.
export default function HomePage() {
return (
<main>
<h1>PYRE</h1>
<p>Burn the dead. Feed the PYRE. Claim the Spawn.</p>
{/* TODO: wallet connect button + scanner entry point */}
</main>
);
}

3
apps/web/src/globals.d.ts vendored Normal file
View File

@@ -0,0 +1,3 @@
// Ambient declaration so `tsc --noEmit` accepts global CSS imports
// (Next.js handles the actual bundling at build time).
declare module "*.css";

15
apps/web/tsconfig.json Normal file
View File

@@ -0,0 +1,15 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2022"],
"module": "ESNext",
"moduleResolution": "Bundler",
"jsx": "preserve",
"noEmit": true,
"allowJs": true,
"incremental": true,
"plugins": [{ "name": "next" }]
},
"include": ["src", "next-env.d.ts", ".next/types/**/*.ts"],
"exclude": ["node_modules", "dist", ".next"]
}

36
apps/worker/README.md Normal file
View File

@@ -0,0 +1,36 @@
# @pyre/worker
PYRE background worker process. **Skeleton only** — no job logic is implemented
yet (see [`CLAUDE.md`](../../CLAUDE.md), §13).
Stack: Node.js worker + BullMQ + Redis (`ioredis`), with `@pyre/db`,
`@pyre/config`, `@pyre/core`, and `@pyre/prometheus`. AI services are API-based
only — do not run local LLMs or image models.
## Responsibilities (§13)
Slow token metadata enrichment, AI generation jobs, image-prompt generation,
safety checks, ticker/name collision checks, background confirmation tracking,
receipt enrichment.
## Job types to implement — TODO
- [ ] `metadata-lookup` — async token metadata enrichment for scanned accounts.
- [ ] `prometheus-generate` — AI Spawn generation (name/ticker/lore/image prompt)
via `@pyre/prometheus`.
- [ ] `safety-check` — moderation + forbidden-term + ticker/name collision checks.
- [ ] `tx-confirmation-watch` — track on-chain confirmation of submitted txs.
- [ ] `receipt-enrichment` — enrich stored cleanup receipts post-confirmation.
## AI safety rules (§16)
Filter generated names/tickers/lore; avoid hate, explicit, extremist,
copyrighted, impersonation, and scam-like outputs; require human approval before
first launches.
## Scripts
- `dev``tsx watch src/index.ts`
- `build``tsc -p tsconfig.json`
- `typecheck``tsc --noEmit`
- `lint` / `test` — placeholders for now

27
apps/worker/package.json Normal file
View File

@@ -0,0 +1,27 @@
{
"name": "@pyre/worker",
"version": "0.1.0",
"private": true,
"type": "module",
"description": "PYRE background worker (BullMQ) — async metadata lookup, AI generation, safety checks, tx-confirmation watcher, receipt enrichment.",
"scripts": {
"build": "tsc -p tsconfig.json",
"dev": "tsx watch src/index.ts",
"typecheck": "tsc --noEmit",
"lint": "echo \"TODO: lint\"",
"test": "echo \"TODO: tests\""
},
"dependencies": {
"@pyre/config": "workspace:*",
"@pyre/core": "workspace:*",
"@pyre/db": "workspace:*",
"@pyre/prometheus": "workspace:*",
"bullmq": "^5.34.0",
"ioredis": "^5.4.2"
},
"devDependencies": {
"@types/node": "^22.10.0",
"tsx": "^4.19.2",
"typescript": "^5.7.2"
}
}

26
apps/worker/src/index.ts Normal file
View File

@@ -0,0 +1,26 @@
// PYRE background worker — SKELETON ONLY.
//
// Minimal bootstrap stub. No queues or processors are wired up yet, and no real
// job logic is implemented. AI services are API-based only (§11) — never run
// local LLMs or image models on the server.
// TODO: construct the Redis connection (ioredis) from @pyre/config and create a
// BullMQ Worker per queue below, each delegating to a typed processor.
//
// Job types to implement (§13):
// - metadata-lookup : async token metadata enrichment for scanned accounts
// - prometheus-generate : AI Spawn generation via @pyre/prometheus
// - safety-check : moderation + forbidden-term + ticker/name collision checks
// - tx-confirmation-watch : background tracking of on-chain tx confirmation
// - receipt-enrichment : enrich stored cleanup receipts post-confirmation
//
// AI safety (§16): filter generated names/tickers/lore; block hate, explicit,
// extremist, copyrighted, impersonation, and scam-like outputs; require human
// approval before any launch.
function main(): void {
// TODO: start BullMQ workers and register graceful shutdown handlers.
console.log("@pyre/worker: skeleton bootstrap — no jobs registered yet");
}
main();

View File

@@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}

489
docs/ARCHITECTURE.md Normal file
View File

@@ -0,0 +1,489 @@
# PYRE — Engineering Architecture
> Companion to [`PYRE_MVP_DESIGN.md`](./PYRE_MVP_DESIGN.md). The design document is
> the canonical source of truth; this file describes *how the system is wired
> together*. Where they appear to disagree, the design document wins.
**Tagline:** *Burn the dead. Feed the PYRE. Claim the Spawn.*
---
## 1. System Overview
PYRE is a Solana wallet-cleanup and ritual meme-rebirth protocol. The MVP runs as
three runtime services backed by two stateful stores, and it depends on two
classes of external service: a Solana RPC provider and AI APIs.
Runtime services:
- **`apps/web`** (`pyre-web`) — Next.js frontend. Wallet connect, scanner UI,
cleanup preview, signing, receipt rendering, Prometheus review, admin pages.
- **`apps/api`** (`pyre-api`) — Node.js/Fastify (or Express) HTTP API. Scan
coordination, classification, **unsigned** transaction building, receipt
storage, AI orchestration, admin API. The only service the browser talks to.
- **`apps/worker`** (`pyre-worker`) — Node.js BullMQ worker. Slow/async jobs:
metadata enrichment, AI generation, image prompts, safety/collision checks,
confirmation tracking, receipt enrichment.
Stateful stores:
- **PostgreSQL** — durable record of scans, classifications, receipts,
generations, and Spawn records.
- **Redis** — BullMQ job queue, scan cache, rate limiting, quote cache,
generation status.
External dependencies (never self-hosted on the MVP VPS):
- **Solana RPC** — external provider only. No validator/RPC node on the VPS.
- **AI APIs** — text, image, and moderation APIs only. No local LLM/image models.
### Component / Data-Flow Diagram
```
┌──────────────┐
│ Wallet │ (Phantom / Solflare via Wallet Adapter)
│ (browser) │ signs locally — keys never leave the client
└──────┬───────┘
│ connect / sign / send
┌──────────────┐ static assets / SSR
│ apps/web │◀───────────────────────────┐
│ (Next.js) │ │
└──────┬───────┘ │
│ HTTPS (JSON) │
▼ │
┌───────────────────────────────────────────────┐ │
│ apps/api │ │
│ scan · classify · build (UNSIGNED) · receipt │ │
│ prometheus/generate · admin │ │
└───┬─────────────┬──────────────┬────────────────┘ │
│ │ │ │
│ SQL │ cache/queue │ getAccounts / simulate / │
▼ ▼ │ sendTx / confirm │
┌──────────┐ ┌──────────┐ ▼ │
│ Postgres │ │ Redis │ ┌──────────────┐ │
│ │ │ (BullMQ) │ │ Solana RPC │ (external) │
└──────────┘ └────┬─────┘ └──────────────┘ │
│ │
│ jobs pulled from queue │
▼ │
┌──────────────┐ ┌──────────────┐ │
│ apps/worker │───▶│ AI APIs │ (external) │
│ (BullMQ) │ │ text/image/ │ │
│ │ │ moderation │ │
└──────┬───────┘ └──────────────┘ │
│ writes results / status │
├───────────────▶ Postgres │
└───────────────▶ Redis ────────────────────┘
(generation status read back by web/api)
```
The browser only ever talks to `apps/web` and `apps/api`. The worker is not
network-exposed; it consumes jobs from Redis and writes results back to Postgres
and Redis. RPC and AI calls flow outbound only.
---
## 2. Component Responsibilities
### `apps/web` — User-facing frontend
Next.js + TypeScript + Tailwind + Solana Wallet Adapter, with React Query or
Zustand for state. Responsibilities (§11):
- Wallet connect via Solana Wallet Adapter.
- Token-account display and classification grouping (closeable / burnable /
transmutable / protected / unsupported).
- User confirmations and **transaction preview** UI.
- Transaction **signing** (client-side, via the connected wallet only).
- Receipt rendering and optional share image.
- Prometheus Spawn-package review and public round/Spawn pages.
- Admin / generation review UI.
### `apps/api` — Backend HTTP API
Node.js + Fastify/Express + TypeScript, fronting PostgreSQL, Redis, BullMQ.
Responsibilities (§11):
- Token-scan coordination (calls RPC, persists results).
- Classification helpers and route evaluation.
- **Builds UNSIGNED Solana transactions** — never signs, never holds keys.
- Metadata preparation and AI generation orchestration (enqueues worker jobs).
- Receipt storage and Spawn-record storage.
- Public API and protected admin API.
### `apps/worker` — Background worker
Node.js worker process driven by BullMQ over Redis, with AI API clients.
Responsibilities (§11):
- Slow token-metadata enrichment.
- AI generation jobs (Prometheus).
- Image-prompt generation.
- Safety checks and ticker/name collision checks.
- Background confirmation tracking.
- Receipt enrichment.
### `packages/core` — Shared types & business logic
The single home for cross-service domain definitions (§13):
- Classification **enums**: `EMPTY_CLOSE_ONLY`, `INCINERATE_ONLY`,
`TRANSMUTABLE`, `PROTECTED_SKIP`, `UNSUPPORTED`.
- Conservative **risk rules** (the §7 safety rules: classic SPL only, skip
Token-2022/NFTs/LP/frozen/delegated, USD threshold, price-impact and stale-quote
guards).
- Shared **DTOs** for the API request/response shapes.
- **Receipt schema**.
- **Prometheus input/output schema**.
### `packages/solana` — Solana transaction helpers
Everything that touches the chain at the instruction level (§13):
- Token-account **parsing** (decode raw account state into the scan model).
- **Close-account** transaction builder.
- **Burn** transaction builder.
- **Simulation** helpers (simulate before signing — §7).
- **Transaction decoder** (decode the built tx so it can be matched against the
preview — §8 step 5, §16).
### `packages/prometheus` — AI generation logic
The creative engine's code (§13), invoked by the worker:
- Prompt **templates**.
- The **meta mixer** (probabilistic influence blend — §9).
- Output **parser**.
- **Safety checks** (blocked terms, scam/impersonation/copyright filters).
- **Image-prompt generator**.
### `packages/db` — Database layer
Schema, migrations, and table definitions (§13/§15). Owns the canonical SQL and
migration history; `apps/api` and `apps/worker` depend on it for data access.
### `packages/config` — Shared config
Shared configuration and environment loading (§13). Centralizes reading
`.env`-supplied secrets (RPC URL, AI keys, DB/Redis connection strings) so no
secret is hard-coded.
### `programs/pyre-core` — Future Anchor program
NOT part of the first burner MVP. The future on-chain trust core (rounds, Essence
vault, claims, refunds) — built only at Phase 7 / v1.0.
---
## 3. Request / Data Flow — The Burner Journey
The core flow is the 8-step burner sequence from §8. The critical trust property:
**the server builds an UNSIGNED transaction, the client signs it, and the decoded
transaction is matched against the preview before signing.**
```
1. Connect ──▶ 2. Scan ──▶ 3. Classify ──▶ 4. Preview ──▶ 5. Build (UNSIGNED)
8. Receipt ◀── 7. Confirm ◀── 6. Sign (client) ◀── decode & match against preview
```
1. **Wallet Connect** — user connects via Solana Wallet Adapter (`apps/web`).
No keys leave the browser.
2. **Account Scan**`apps/web` calls `POST /api/scan`. `apps/api` queries token
accounts via the external RPC, capturing for each: owner, ATA address, mint,
token program, balance, decimals, rent estimate, metadata (if available),
token-program type, frozen/delegated state. Results persist to
`wallet_scans` / `token_accounts`; slow metadata enrichment may be deferred to
a worker job. Scan results are cached in Redis.
3. **Classification** — each account is classified server-side into the §6
categories and grouped for the UI. **Client-submitted classifications are not
trusted** — the server recomputes where needed (§16).
4. **Preview** — before any signing the user sees: accounts to close, tokens to
burn, accounts skipped, estimated rent returned, transaction fees, warnings,
and the destination wallet for recovered rent (which is the user's own wallet).
5. **Build Transaction**`apps/web` calls `POST /api/build/close-empty` (and/or
`/api/build/burn`). `apps/api` uses `packages/solana` to build an **unsigned**
transaction and returns it base64-encoded plus the preview. The client decodes
the transaction (`packages/solana` decoder) and **matches it against the
preview**; any mismatch aborts before signing.
6. **User Signs** — locally, with the connected wallet. PYRE never requests
private keys and never performs custodial signing.
7. **Confirmation** — the signed transaction is sent and confirmed via RPC. A
worker confirmation-tracking job may follow the signature to durable finality.
8. **Receipt**`apps/web` calls `POST /api/receipt`; `apps/api` records and
returns the receipt: tx signature, accounts closed, tokens burned, rent
returned, accounts skipped, warnings, timestamp, optional share image. A worker
receipt-enrichment job may backfill metadata.
All transactions are simulated before final signing (§7), and all build requests
are logged (§16).
---
## 4. API Surface
Reproduced from §14. All endpoints are served by `apps/api`. Admin endpoints are
authenticated and protected separately (§16).
### `POST /api/scan`
```jsonc
// in:
{ "wallet": "wallet_pubkey" }
// out:
{
"scanId": "uuid",
"wallet": "wallet_pubkey",
"summary": {
"totalAccounts": 0,
"emptyCloseOnly": 0,
"incinerateOnly": 0,
"transmutable": 0,
"protectedSkip": 0,
"unsupported": 0,
"estimatedRentLamports": 0
},
"accounts": []
}
```
### `POST /api/build/close-empty`
```jsonc
// in:
{ "wallet": "...", "accountAddresses": ["ata1", "ata2"] }
// out:
{
"transactionBase64": "...",
"preview": {
"accountsToClose": [],
"estimatedRentReturnedLamports": 0,
"rentDestination": "user_wallet_pubkey"
}
}
```
### `POST /api/build/burn`
```jsonc
// in:
{ "wallet": "...", "items": [{ "tokenAccount": "...", "mint": "...", "amount": "..." }] }
// out:
{
"transactionBase64": "...",
"preview": {
"tokensToBurn": [],
"accountsPotentiallyClosable": []
}
}
```
### `POST /api/receipt`
```jsonc
// in:
{ "wallet": "...", "txSignature": "...", "scanId": "uuid" }
// out:
{
"receiptId": "uuid",
"txSignature": "...",
"rentReturnedLamports": 0,
"closedAccounts": [],
"burnedTokens": [],
"skippedTokens": []
}
```
### `POST /api/prometheus/generate`
```jsonc
// in:
{ "receiptId": "uuid", "chaos": 0.25, "operatorSeed": "optional" }
// out:
{
"generationId": "uuid",
"spawnName": "...",
"ticker": "...",
"lore": "...",
"imagePrompt": "...",
"metadata": {},
"riskFlags": []
}
```
### Admin endpoints
Admin / generation-review endpoints (approve/reject generations, record Pump.fun
launches, view system events) are protected and not part of the public surface.
They back the admin review UI and the Spawn-record workflow (§10, §16).
---
## 5. Data Model
### Initial PostgreSQL tables (§15)
```
wallet_scans: id, wallet, status, created_at, completed_at, summary_json
token_accounts: id, scan_id, wallet, ata, mint, token_program,
raw_balance, ui_balance, decimals, symbol, name,
classification, warnings_json, estimated_rent_lamports,
created_at
cleanup_receipts: id, wallet, scan_id, tx_signature, rent_returned_lamports,
closed_accounts_count, burned_tokens_count, status,
created_at, receipt_json
prometheus_generations: id, receipt_id, input_json, output_json, status,
risk_flags_json, created_at, approved_at, rejected_at
spawn_records: id, generation_id, spawn_name, ticker, mint, metadata_uri,
pumpfun_url, launch_tx, status, created_at
```
Additional initial tables called out in §11/§15: `token_classifications`,
`burn_events`, `close_account_events`, `spawn_candidates`, and `system_events`
(audit/event log).
### Future tables (NOT in the burner MVP)
These arrive with the Essence ledger and PYRE Core program (Phases 67):
- `pyre_rounds` — round state machine.
- `essence_contributions` — recorded Essence per wallet per round.
- `claim_records` — Spawn claim accounting.
- `refund_records` — refunds for failed rounds.
- `influence_fields` — meta-influence inputs for Prometheus weighting.
> Per §5/§15: Essence may start in the database, but it must not be called a
> deposit until an on-chain custody model exists, and claims must not be promised
> until claim logic exists.
---
## 6. Redis Usage
Redis serves five roles (§11):
- **Job queue** — backs BullMQ; `apps/api` enqueues, `apps/worker` consumes.
- **Scan cache** — caches scan results so repeat views don't re-hit RPC.
- **Rate limiting** — throttles scan and build endpoints (§16).
- **Temporary quote cache** — short-lived swap/route quotes; stale quotes are
rejected by classification (§7).
- **Generation status** — live status of in-flight Prometheus jobs, read back by
`apps/web` / `apps/api`.
### BullMQ Worker Jobs
`apps/worker` processes these job types (§11):
- **Metadata enrichment** — slow token name/symbol/metadata lookups.
- **AI generation** — Prometheus Spawn generation.
- **Image prompts** — image-prompt generation for the Spawn.
- **Safety checks** — moderation of generated names/tickers/lore.
- **Collision checks** — ticker/name duplicate detection.
- **Confirmation tracking** — follow tx signatures to finality in the background.
- **Receipt enrichment** — backfill receipt detail after confirmation.
---
## 7. Solana RPC Requirements
PYRE uses an **external RPC provider only**. Per §11/§12, the MVP VPS must **not**
run a Solana validator or RPC node.
Required RPC capabilities (§11):
- Get token accounts by owner.
- Get account info.
- Simulate transactions.
- Send transactions.
- Confirm transactions.
- Parse token-account state.
The RPC endpoint URL is supplied via environment config (`packages/config`) and
treated as a secret. All chain access flows through `packages/solana`.
---
## 8. AI Services
AI is **API-based only** (§11/§12). The MVP server must **not** run local LLMs or
local image-generation models.
Service classes used:
- **Text generation** — Spawn name, ticker, lore, tagline, description, launch
copy (§9 outputs).
- **Image generation** — from the generated image prompt.
- **Moderation / safety** — filtering hate/explicit/extremist/copyrighted/
impersonation/scam-like output (§16).
All AI calls are made from `apps/worker` using clients configured via secrets in
`packages/config`. Prometheus generates a *candidate package for human review*
it never launches tokens or controls funds (§9).
---
## 9. Infrastructure & Deployment
A single **8GB VPS** is sufficient for the MVP (§12). It runs:
- `pyre-web`, `pyre-api`, `pyre-worker`
- PostgreSQL
- Redis
- **nginx** (reverse proxy / TLS termination in front of web + api)
- **PM2 or systemd** (process supervision for the three Node services)
- logs / log rotation
- admin dashboard
The VPS must **NOT** run (§12):
- a Solana validator,
- a Solana RPC node,
- a large local LLM,
- local image generation,
- heavy indexing at scale.
**Base setup already completed (§12/§19):** `pyre` user created, root login
disabled, SSH key auth, UFW firewall, Fail2ban, basic hardening.
**Next setup (§12/§19):** Node.js 22, pnpm, Git, nginx, PostgreSQL, Redis, PM2,
Claude Code, project repo, environment files, backup script, log rotation.
**External accounts required (§19):** Solana RPC provider, OpenAI/Anthropic API
key, image-generation provider, domain name, GitHub repo, Pump.fun creator
wallet, optional IPFS/Arweave metadata service.
---
## 10. Build-Order Note (Phased Roadmap)
Components map to the §18 development phases so a reader knows *what gets built
when*:
| Phase | Focus | Components touched |
|-------|-------|--------------------|
| **0 — Server & Repo Setup** | VPS, pnpm workspace, web/api/worker skeletons, Postgres + Redis, nginx, env templates | all apps (skeleton), `packages/config`, `infra/` |
| **1 — Wallet Scanner** | Wallet connect, scan endpoint, token-account fetch, basic classification, results + protected/skipped UI | `apps/web`, `apps/api`, `packages/solana` (parsing), `packages/core` (enums/rules), `packages/db` (`wallet_scans`, `token_accounts`) |
| **2 — Close Empty ATAs** | Build close-account tx, decode/preview, signing, confirmation tracking, receipt page | `packages/solana` (close builder + decoder + simulation), `apps/api` (`/build/close-empty`, `/receipt`), `apps/worker` (confirmation tracking), `packages/db` (`cleanup_receipts`, `close_account_events`) |
| **3 — Burn Junk** | `INCINERATE_ONLY` classification, burn builder, burn-then-close, stronger confirmations, receipt update | `packages/solana` (burn builder), `apps/api` (`/build/burn`), `packages/db` (`burn_events`) |
| **4 — Prometheus Generator** | Generation input from receipt, meta mixer, name/ticker/lore + image prompt, safety checks, admin approval UI | `packages/prometheus`, `apps/worker` (AI/safety/collision jobs), `apps/api` (`/prometheus/generate`, admin), `apps/web` (review UI), `packages/db` (`prometheus_generations`, `spawn_candidates`) |
| **5 — Manual Pump.fun Launch** | Approved package, metadata JSON, operator checklist, record mint/url/tx, public Spawn page | `apps/web` (public Spawn page), `apps/api` (admin record endpoints), `packages/db` (`spawn_records`) |
| **6 — Essence / Round Prototype** | Swap-candidate detection, route quote preview, net Essence estimate, round dashboard, DB-only contribution record (no claim promises) | `packages/solana` (route eval), `apps/api`, `packages/db` (future `pyre_rounds`, `essence_contributions`, `influence_fields`) |
| **7 — PYRE Core Program** | Anchor program: create round, contribute Essence, contribution-receipt PDA, lock round, register Spawn, claim, refund, tests | `programs/pyre-core`, future tables `claim_records`, `refund_records` |
The first three phases deliver the trust-building burner (v0.1). The Anchor
program in `programs/pyre-core` is explicitly **not** needed until Phase 7 / v1.0.
---
> **PYRE returns your rent. The scraps feed the fire.**

559
docs/PYRE_MVP_DESIGN.md Normal file
View File

@@ -0,0 +1,559 @@
# PYRE / Prometheus Protocol — MVP Design Document
> Canonical source of truth for the PYRE MVP. This document is reproduced from
> the original design brief. When in doubt, this file wins.
**Tagline:** *Burn the dead. Feed the PYRE. Claim the Spawn.*
---
## 1. Project Summary
PYRE is a Solana wallet-cleanup and ritual meme rebirth protocol.
Users connect a Solana wallet. PYRE scans SPL token accounts for empty
accounts, abandoned balances, dust tokens, scam tokens, illiquid remnants, and
unsupported assets. The system classifies each token account and helps the user
safely perform cleanup actions.
The initial MVP focuses on **wallet cleanup and trust**:
1. Scan the user wallet.
2. Identify token accounts.
3. Classify assets as safe-to-close, burnable, transmutable, or protected.
4. Let the user close empty associated token accounts.
5. Return recovered ATA rent to the user.
6. Generate a clear PYRE receipt.
The later ritual layer uses **Prometheus**, an AI firebringer engine, to
generate a new meme token identity (a **Spawn**) from burned/transmuted token
remnants. The first launch flow is semi-manual through Pump.fun before full
protocol automation is attempted.
> The MVP should **not** start as a fully automated on-chain launch protocol. It
> should start as a safe burner/cleaner with a beautiful receipt experience.
---
## 2. Core Product Positioning
PYRE is **not** an investment product, yield mechanism, trading bot,
guaranteed-profit system, or protected launch mechanism.
PYRE **is**: wallet cleanup, token scrap transmutation, recovered rent return,
transparent contribution accounting, AI-generated meme rebirth, and ritual
entertainment.
> PYRE cleans dead Solana remnants from your wallet, returns recovered rent to
> you, and optionally lets safely swapped scraps feed a ritual round that
> Prometheus uses to birth a new AI-generated Spawn.
---
## 3. Core Trust Rule
> **Recovered ATA rent returns to the user by default.**
Rent must not be silently taxed, redirected, pooled, or used as Essence unless a
future version creates an explicit opt-in donation mode.
For MVP:
- recovered rent goes to the user,
- burned junk does not count as Essence,
- swapped scraps may become Essence **only if the user explicitly approves**,
- optional SOL contribution must be separate and explicit,
- all actions require wallet approval,
- **PYRE never has custody of private keys.**
> **PYRE returns your rent. The scraps feed the fire.**
---
## 4. MVP Philosophy
Narrow, practical, and trust-building. Do **not** build the full ritual launch
protocol first.
Build this first:
```
Connect wallet
→ scan token accounts
→ classify accounts
→ close eligible empty ATAs
→ optionally burn obvious junk
→ return rent to user
→ show receipt
```
Then add:
```
Burned/transmuted token metadata
→ Prometheus AI generation
→ manual Pump.fun launch package
```
Then later add:
```
Essence ledger
→ contribution proofs
→ round state machine
→ Spawn distribution
→ claim logic
```
The first emotional win: *"PYRE cleaned my wallet and returned SOL I forgot was
trapped in token accounts."* That trust moment makes the later ritual layer
believable.
---
## 5. MVP Feature Scope
### MVP v0.1 — Burner / Cleaner
**Required:**
- Solana wallet connect
- Read token accounts
- Detect empty associated token accounts
- Estimate reclaimable rent
- Classify obvious protected assets
- Build close-account transactions
- User signs locally
- Send rent back to user wallet
- Display transaction result
- Generate PYRE receipt
**Optional but desirable:** detect burnable junk tokens; allow user to burn
selected junk to zero; close emptied accounts after burn; show
skipped/protected tokens; export/share receipt image.
**v0.1 must NOT include:** automatic Pump.fun launch, user-contributed Essence
vault, custom PYRE Solana program, Token-2022 support, NFT handling, automatic
valuable-token sacrifice, custodial signing, background wallet automation.
### MVP v0.2 — Prometheus Meta Mixer
AI generation from burned/cleaned token context.
**Input:** token names, symbols, metadata, categories, burned count,
transmutable count, source archetypes, optional theme seed, chaos factor.
**Output:** spawn name, ticker, lore, tagline, image prompt, metadata
description, Pump.fun launch description, risk/safety warnings, forbidden-term
check, duplicate ticker/name check.
Prometheus must **not** directly launch tokens — it generates a candidate
package for human review.
### MVP v0.3 — Manual Pump.fun Creator Workflow
```
Burner receipt → Prometheus generates Spawn package → human reviews package
→ human manually creates Pump.fun token → PYRE records mint, launch URL,
metadata, tx → public Spawn record page
```
Validates metadata/art/ticker quality, the Pump.fun creation process, user
understanding, and social reaction without dangerous automation.
### MVP v0.4 — Essence Ledger
```
safe scrap swap output → net SOL value → record as Essence
→ associate with wallet and round → show round progress
```
Can start in a database before moving on-chain. **Important:** do not call it a
deposit until an on-chain custody model exists; do not promise claims until
claim logic exists; keep it experimental if not on-chain.
### MVP v1.0 — PYRE Core Program
Custom Solana program for trust-critical accounting: create round, accept
Essence, hold Essence vault, record contribution receipts, lock round, register
Spawn mint, open claims, distribute Spawn pro rata, support refunds for failed
rounds, prevent double claims. This is where PYRE becomes a true protocol.
---
## 6. Token Classification
Token accounts are classified into conservative categories.
- **EMPTY_CLOSE_ONLY** — zero balance, can be closed. *Action:* close ATA, send
rent to user wallet.
- **INCINERATE_ONLY** — no safe swap route but may be burnable. *Action:* user
may burn balance to zero; if account becomes empty, close it; recovered rent
returns to user.
- **TRANSMUTABLE** — has a safe swap route and passes risk checks. *Action:* user
may swap token into SOL; net swapped SOL may become Essence **only if the user
opts in**.
- **PROTECTED_SKIP** — not touched by default. Examples: SOL/WSOL special cases,
USDC/USDT/major assets, valuable meme tokens, NFTs, LP tokens, receipt tokens,
staked tokens, suspicious tokens, frozen accounts, delegated accounts,
high-value balances.
- **UNSUPPORTED** — system cannot safely reason about it. Examples: Token-2022 in
MVP, unknown token program, bad metadata, unsupported account layout, accounts
with extension behavior not yet handled.
> **Default rule: Unknown means skip.**
---
## 7. Token Safety Rules
The classifier must be conservative. MVP rules:
- Classic SPL only.
- Skip Token-2022 by default.
- Skip NFTs.
- Skip compressed NFTs.
- Skip LP tokens.
- Skip frozen accounts.
- Skip delegated accounts.
- Skip known valuable assets.
- Skip tokens above a user-safe USD threshold.
- Skip routes with high price impact.
- Skip routes with stale quotes.
- Skip unsafe or weird liquidity paths.
- Simulate all transactions before final signing.
> The system should never say *"This token is safe."*
> It should say *"This token appears eligible based on current checks."*
---
## 8. Burner Transaction Flow
1. **Wallet Connect** — user connects via Solana Wallet Adapter.
2. **Account Scan** — query token accounts. For each: owner, ATA address, mint,
token program, balance, decimals, rent estimate, metadata if available, token
program type, frozen/delegated state if available.
3. **Classification** — each account classified; UI groups into: closeable empty
accounts, burnable junk, potentially transmutable scraps, protected/skipped,
unsupported.
4. **Preview** — before signing the user sees: accounts to close, tokens to burn,
accounts skipped, estimated rent returned, transaction fees, warnings,
destination wallet for recovered rent.
5. **Build Transaction** — backend/frontend builds an unsigned Solana
transaction. It must be decoded and compared against the preview.
6. **User Signs** — locally, with the wallet. PYRE must never ask for private keys.
7. **Confirmation** — system waits for transaction confirmation.
8. **Receipt** — shows tx signature, accounts closed, tokens burned, rent
returned, accounts skipped, warnings, timestamp, optional share image.
---
## 9. Prometheus AI Meta Mixer
Prometheus is the creative engine. It generates Spawn identity, **not** control
of funds.
**Input:** `burned_tokens[]`, `transmuted_tokens[]`, `token_symbols[]`,
`token_names[]`, `metadata_descriptions[]`, `dominant_archetypes[]`,
`chaos_factor`, `manual_theme_seed_optional`.
**Output:** `spawn_name`, `spawn_ticker`, `spawn_lore`, `spawn_tagline`,
`spawn_description`, `image_prompt`, `metadata_json`, `launch_copy`, `risk_flags`.
**Meta influence** (probabilistic, not deterministic) — example model:
```
40% burned token archetypes
25% Essence-weighted token themes
20% Prometheus mutation / chaos
15% manual operator seed
```
Do not allow users to force exact copyrighted or existing meme identities.
- Bad: *"Create a Pepe token."*
- Better: *"Frog archetype influence increased."*
Prometheus should create inspired mutations, not direct clones.
---
## 10. Pump.fun Creator Workflow
The first Pump.fun integration is manual / approval-gated.
**Manual MVP flow:** Prometheus generates token package → operator reviews →
operator creates token on Pump.fun → operator records mint and launch link →
PYRE shows Spawn record.
**Semi-automated future:** generates package → backend uploads metadata →
backend builds create transaction → creator/multisig signs → token launches →
PYRE records launch.
**Fully automated future** (NOT MVP): round locks → Prometheus generates Spawn →
metadata uploaded → launch tx built → Essence used for initial acquisition →
Spawn distributor receives tokens → contributors claim pro rata.
---
## 11. Architecture
**Frontend** — Next.js, TypeScript, Tailwind, Solana Wallet Adapter, React Query
or Zustand, transaction preview UI, receipt UI, admin/generation UI.
*Responsibilities:* wallet connect, token account display, classification
grouping, user confirmations, transaction signing, receipt rendering, Spawn
package review, public round/spawn pages.
**Backend API** — Node.js, Fastify or Express, TypeScript, PostgreSQL, Redis,
BullMQ. *Responsibilities:* token scan coordination, classification helpers,
route evaluation, AI generation orchestration, metadata preparation, receipt
storage, Spawn record storage, public API, admin API.
**Worker** — Node.js worker process, BullMQ queue, Redis, AI API clients.
*Responsibilities:* slow token metadata enrichment, AI generation jobs, image
prompt generation, safety checks, ticker/name collision checks, background
confirmation tracking, receipt enrichment.
**Database** — PostgreSQL.
*Initial tables:* `wallet_scans`, `token_accounts`, `token_classifications`,
`cleanup_receipts`, `burn_events`, `close_account_events`,
`prometheus_generations`, `spawn_candidates`, `spawn_records`, `system_events`.
*Future tables:* `pyre_rounds`, `essence_contributions`, `claim_records`,
`refund_records`, `influence_fields`.
**Redis** — job queue, scan cache, rate limiting, temporary quote cache,
generation status.
**Solana RPC** — external provider. Do **not** run a validator/RPC node on the
MVP VPS. Required: get token accounts by owner, get account info, simulate
transactions, send transactions, confirm transactions, parse token account state.
**AI Services** — API-based first (text generation, image generation,
moderation/safety, custom prompt templates). Do **not** run local LLMs or image
models on the MVP server.
---
## 12. Server / Infrastructure Setup
An 8GB VPS is enough for the MVP. Run: `pyre-web`, `pyre-api`, `pyre-worker`,
postgres, redis, nginx, pm2 or systemd, logs, admin dashboard.
Do **not** run: a Solana validator, a Solana RPC node, a large local LLM, local
image generation, or heavy indexing at scale.
**Server base setup — already completed:** new user `pyre`, root disabled, SSH
key auth, UFW configured, Fail2ban installed, basic security hardening.
**Next setup:** Node.js 22, pnpm, Git, nginx, PostgreSQL, Redis, PM2, Claude
Code, project repo, environment files, backup script, log rotation.
---
## 13. Recommended Repo Structure
```
pyre/
apps/
web/
api/
worker/
packages/
core/
solana/
prometheus/
db/
config/
programs/
pyre-core/
docs/
PYRE_MVP_DESIGN.md
ARCHITECTURE.md
SECURITY.md
TOKEN_CLASSIFICATION.md
scripts/
infra/
preview.html
CLAUDE.md
package.json
pnpm-workspace.yaml
```
- **apps/web** — user-facing app: landing, wallet connect, scanner UI, cleanup
preview, receipt page, Prometheus generation preview, admin review page.
- **apps/api** — backend HTTP API: scan, classify, build transaction, receipt,
generation, admin endpoints.
- **apps/worker** — background workers: async metadata lookup, AI generation,
safety checks, tx confirmation watcher, receipt enrichment.
- **packages/core** — shared types and business logic: classification enums,
risk rules, shared DTOs, receipt schema, Prometheus input/output schema.
- **packages/solana** — Solana transaction helpers: token account parsing,
close-account tx builder, burn tx builder, simulation helpers, tx decoder.
- **packages/prometheus** — AI generation logic: prompt templates, meta mixer,
output parser, safety checks, image prompt generator.
- **packages/db** — database schema, migrations, table definitions.
- **packages/config** — shared config and environment loading.
- **programs/pyre-core** — future Anchor program (NOT needed for the first burner
MVP).
---
## 14. API Design
```http
POST /api/scan
# in: { "wallet": "wallet_pubkey" }
# out: { scanId, wallet, summary: { totalAccounts, emptyCloseOnly,
# incinerateOnly, transmutable, protectedSkip, unsupported,
# estimatedRentLamports }, accounts: [] }
POST /api/build/close-empty
# in: { "wallet": "...", "accountAddresses": ["ata1","ata2"] }
# out: { transactionBase64, preview: { accountsToClose,
# estimatedRentReturnedLamports, rentDestination } }
POST /api/build/burn
# in: { "wallet": "...", "items": [{ tokenAccount, mint, amount }] }
# out: { transactionBase64, preview: { tokensToBurn, accountsPotentiallyClosable } }
POST /api/receipt
# in: { "wallet": "...", "txSignature": "...", "scanId": "uuid" }
# out: { receiptId, txSignature, rentReturnedLamports, closedAccounts,
# burnedTokens, skippedTokens }
POST /api/prometheus/generate
# in: { "receiptId": "uuid", "chaos": 0.25, "operatorSeed": "optional" }
# out: { generationId, spawnName, ticker, lore, imagePrompt, metadata, riskFlags }
```
---
## 15. MVP Database Schema
```
wallet_scans: id, wallet, status, created_at, completed_at, summary_json
token_accounts: id, scan_id, wallet, ata, mint, token_program,
raw_balance, ui_balance, decimals, symbol, name,
classification, warnings_json, estimated_rent_lamports,
created_at
cleanup_receipts: id, wallet, scan_id, tx_signature, rent_returned_lamports,
closed_accounts_count, burned_tokens_count, status,
created_at, receipt_json
prometheus_generations: id, receipt_id, input_json, output_json, status,
risk_flags_json, created_at, approved_at, rejected_at
spawn_records: id, generation_id, spawn_name, ticker, mint, metadata_uri,
pumpfun_url, launch_tx, status, created_at
```
(Also: `token_classifications`, `burn_events`, `close_account_events`,
`spawn_candidates`, `system_events`.)
---
## 16. Security Requirements
**Wallet Security:** Never request private keys. Never run custodial signing.
Never auto-execute without user signing. Always show transaction preview. Decode
transaction before signing. Match decoded transaction against preview.
**Token Safety:** Unknown assets default to skip. Token-2022 default skip for
MVP. NFTs default skip. Valuable assets default skip. User must manually select
anything risky. High-value actions require stronger confirmation.
**Backend Security:** Rate-limit scan endpoints. Validate wallet pubkeys.
Validate token account ownership. Do not trust client-submitted classifications;
recompute server-side where needed. Log all transaction build requests. Protect
admin endpoints. Use environment secrets only. Rotate API keys if leaked.
**AI Safety:** Filter generated names, tickers, lore. Avoid hate, explicit,
extremist, copyrighted, impersonation, and scam-like outputs. Require human
approval before first launches.
---
## 17. Abuse Scenarios
- **Misclassification of valuable asset** → user loses valuable token. *Defense:*
protected token registry, USD value threshold, major-token skip list, manual
advanced override only.
- **Fake dust farming** → user creates many fake tokens to influence status.
*Defense:* no allocation by token count, no reward by account count, Essence
weighting only in future versions.
- **Rent confusion** → people claim PYRE steals rent. *Defense:* receipt clearly
shows rent returned, transaction preview clearly shows destination, do not pool
rent by default.
- **AI output abuse** → Prometheus generates offensive/copyrighted token.
*Defense:* safety filters, blocked terms, ticker collision checks, human
approval in MVP.
- **Pump.fun launch abuse** → Spawn launches look like team-rug launches.
*Defense:* manual review, public launch record, no profit promises, clear
entertainment framing, disclose launch wallet / creator.
---
## 18. MVP Development Phases
- **Phase 0 — Server and Repo Setup:** VPS configured, Claude Code installed,
repo initialized, pnpm workspace created, web/api/worker skeleton, Postgres +
Redis running, nginx configured, environment templates.
- **Phase 1 — Wallet Scanner:** wallet connect frontend, scan endpoint, token
account fetch, basic classification, scan results UI, protected/skipped UI.
- **Phase 2 — Close Empty ATAs:** identify empty token accounts, build
close-account tx, decode tx preview, wallet signing, confirmation tracking,
receipt page.
- **Phase 3 — Burn Junk:** incinerate-only classification, burn transaction
builder, burn-then-close flow, stronger confirmations, receipt update.
- **Phase 4 — Prometheus Generator:** generation input from receipt, meta mixer,
Spawn name/ticker/lore generation, image prompt generation, safety checks,
admin approval UI.
- **Phase 5 — Manual Pump.fun Launch Workflow:** approved Spawn package, metadata
JSON, operator launch checklist, mint/url/tx record input, public Spawn record
page.
- **Phase 6 — Essence / Round Prototype:** safe swap candidate detection, route
quote preview, net Essence estimate, round dashboard, contribution database
record, no claim promises until on-chain logic exists.
- **Phase 7 — PYRE Core Program:** Anchor program — create round, contribute
Essence, contribution receipt PDA, lock round, register Spawn, claim Spawn,
refund failed round, tests.
---
## 19. What We Need Set Up Now
**Server — already done:** pyre user, SSH auth key, root disabled, UFW, Fail2ban.
**Server — next:** Node.js 22, pnpm, Git, nginx, PostgreSQL, Redis, PM2, Claude
Code, repo directory, .env files, backup script, logrotate config.
**External accounts / services:** Solana RPC provider, OpenAI/Anthropic API key,
image generation provider, domain name, GitHub repo, Pump.fun creator wallet,
optional IPFS/Arweave metadata service.
**Local / dev tools:** VS Code or SSH workflow, Claude Code, Git, Node.js, pnpm,
Postgres client, Redis CLI, Solana CLI (later), Anchor (later).
**Project files to create:** `CLAUDE.md`, `README.md`, `docs/PYRE_MVP_DESIGN.md`,
`docs/SECURITY.md`, `docs/TOKEN_CLASSIFICATION.md`, `.env.example`,
`pnpm-workspace.yaml`.
---
## 20. First Claude Code Prompts
After repo + CLAUDE.md exist, **plan first (no code):**
> Read CLAUDE.md and docs/PYRE_MVP_DESIGN.md. Do not write code yet. Produce an
> implementation plan for PYRE MVP v0.1 focused only on wallet scanning, token
> account classification, close-empty-ATA transaction building, transaction
> preview, and receipt generation. Identify the exact packages, APIs, database
> tables, and test cases needed.
Then, after plan review (**skeleton only**):
> Create the monorepo skeleton with pnpm workspaces. Add apps/web, apps/api,
> apps/worker, packages/core, packages/solana, packages/prometheus, packages/db,
> and docs. Add TypeScript configs, package.json files, README files, and
> .env.example files. Do not implement Solana transaction logic yet.
---
## 21. MVP Definition of Done
The MVP is complete when a user can: connect wallet, scan token accounts, see
clear classifications, select empty ATAs, preview the close-account transaction,
sign it, recover rent to their wallet, see a receipt, generate a Prometheus Spawn
concept from the receipt, manually record a Pump.fun launch, and view a public
Spawn record page.
> The MVP is **not** complete if it requires users to trust hidden backend logic.
The MVP succeeds if users say: *"This cleaned my wallet, returned SOL, and the
receipt/generation was cool."* That is the foundation for the full PYRE protocol.

128
docs/SECURITY.md Normal file
View File

@@ -0,0 +1,128 @@
# Security
> Security model and threat documentation for PYRE. Aligned with
> [`PYRE_MVP_DESIGN.md`](PYRE_MVP_DESIGN.md) §3, §16, and §17 — when in doubt, the
> design doc wins.
PYRE is a wallet-cleanup tool. Its entire value proposition rests on trust:
users connect a wallet and let PYRE help them destroy or close token accounts.
That only works if PYRE can never harm the user, never take custody of funds, and
never hide what it is doing.
---
## Core trust rule
> **Recovered ATA rent returns to the user by default.**
Rent must **never** be silently taxed, redirected, pooled, or counted as Essence
unless a future version creates an explicit opt-in donation mode.
For the MVP:
- Recovered rent goes to the user.
- Burned junk does **not** count as Essence.
- Swapped scraps may become Essence **only if the user explicitly approves**.
- Any optional SOL contribution must be separate and explicit.
- All actions require wallet approval.
- **PYRE never has custody of private keys.**
> **PYRE returns your rent. The scraps feed the fire.**
---
## Wallet security
- **Never request private keys.**
- **Never run custodial signing.**
- **Never auto-execute without the user signing** locally in their own wallet.
- **Always show a transaction preview** before any signature is requested.
- **Decode the transaction before signing.**
- **Match the decoded transaction against the preview** (accounts to close,
tokens to burn, rent amount, rent destination, fees, warnings). If the decoded
transaction does not match the preview, do not sign.
---
## Token safety
- Unknown assets default to **skip**.
- Token-2022 defaults to **skip** for the MVP.
- NFTs default to **skip**.
- Valuable assets default to **skip**.
- The user must **manually select** anything risky.
- High-value actions require **stronger confirmation**.
For the full classifier specification — categories, allowed actions, the
"Unknown means skip" rule, and the complete safety checklist — see
[`TOKEN_CLASSIFICATION.md`](TOKEN_CLASSIFICATION.md).
---
## Backend security
- **Rate-limit scan endpoints.**
- **Validate wallet pubkeys.**
- **Validate token-account ownership** (the account must belong to the wallet).
- **Do not trust client-submitted classifications** — recompute classification
server-side before building any transaction.
- **Log all transaction build requests.**
- **Protect admin endpoints.**
- **Use environment secrets only.**
- **Rotate API keys if leaked.**
---
## AI safety
- **Filter** generated names, tickers, and lore.
- **Avoid** hate, explicit, extremist, copyrighted, impersonation, and scam-like
outputs.
- **Require human approval before first launches.** Prometheus generates a
candidate package for human review; it never launches tokens directly.
---
## Abuse scenarios
Reproduced from design doc §17. Each is stated as **Risk → Defense**.
### Misclassification of valuable asset
- **Risk:** The classifier mislabels a valuable token and the user loses it.
- **Defense:** Protected token registry, USD value threshold, major-token skip
list, and manual advanced override only.
### Fake dust farming
- **Risk:** A user creates many fake tokens to inflate their status.
- **Defense:** No allocation by token count, no reward by account count; Essence
weighting only in future versions.
### Rent confusion
- **Risk:** People claim PYRE steals rent.
- **Defense:** The receipt clearly shows rent returned, the transaction preview
clearly shows the destination, and rent is not pooled by default.
### AI output abuse
- **Risk:** Prometheus generates an offensive or copyrighted token.
- **Defense:** Safety filters, blocked terms, ticker collision checks, and human
approval in the MVP.
### Pump.fun launch abuse
- **Risk:** Spawn launches look like team-rug launches.
- **Defense:** Manual review, public launch record, no profit promises, clear
entertainment framing, and disclosure of the launch wallet / creator.
---
## No private keys, anywhere
PYRE is non-custodial by design. There is intentionally **no private-key or
mnemonic environment variable anywhere in the project**, and there never will be.
All signing happens client-side in the user's wallet. Any change that introduces
key custody, mnemonic handling, or custodial signing violates the core trust
rule and must be rejected.

View File

@@ -0,0 +1,186 @@
# Token Classification
> Spec for the PYRE token-account classifier. Aligned with
> [`PYRE_MVP_DESIGN.md`](PYRE_MVP_DESIGN.md) §6 and §7 — when in doubt, the design
> doc wins.
PYRE scans a wallet's SPL token accounts and assigns each one a single
conservative category. The category determines what action (if any) the user is
allowed to take and how recovered rent / Essence are handled.
---
## Philosophy: conservative by default
The classifier exists to protect the user from accidentally destroying value. It
is intentionally cautious. It never optimizes for "more accounts cleaned" at the
cost of safety. When two readings of an account are possible, it picks the safer
(less destructive) one.
> **Default rule: Unknown means skip.**
Anything the system cannot fully and safely reason about — an unknown token
program, bad or missing metadata, an unsupported account layout, unfamiliar
extension behavior — is classified into a non-destructive category
(`PROTECTED_SKIP` or `UNSUPPORTED`) and is **never acted on by default**. The
user must manually opt in to anything risky.
The classifier must never say *"this token is safe."* It may only say
*"this token appears eligible based on current checks."* See
[Wording rule](#wording-rule).
---
## Classification categories
Each token account is assigned exactly one of the following categories. The
canonical enum lives in `packages/core` (see [Canonical enum](#canonical-enum)).
### `EMPTY_CLOSE_ONLY`
- **Enum identifier:** `EMPTY_CLOSE_ONLY`
- **Meaning:** A zero-balance token account that can be closed.
- **Allowed action(s):** Close the associated token account (ATA).
- **Rent / Essence rules:** Recovered ATA rent is sent to the **user's wallet**.
Nothing is counted as Essence.
### `INCINERATE_ONLY`
- **Enum identifier:** `INCINERATE_ONLY`
- **Meaning:** An account with a balance that has no safe swap route but may be
burnable junk.
- **Allowed action(s):** The user may burn the balance to zero; if the account
becomes empty after the burn, it may then be closed.
- **Rent / Essence rules:** Recovered rent (from closing the emptied account)
returns to the **user's wallet**. Burned junk does **not** count as Essence.
### `TRANSMUTABLE`
- **Enum identifier:** `TRANSMUTABLE`
- **Meaning:** An account holding a token that has a safe swap route and passes
the risk checks.
- **Allowed action(s):** The user may swap the token into SOL.
- **Rent / Essence rules:** The net swapped SOL may become Essence **only if the
user explicitly opts in**. Without opt-in, proceeds go to the user. Recovered
rent from any subsequently closed account returns to the user.
### `PROTECTED_SKIP`
- **Enum identifier:** `PROTECTED_SKIP`
- **Meaning:** An account PYRE recognizes but will **not touch by default**
because acting on it could destroy or mishandle value.
- **Allowed action(s):** None by default. Acting on these requires an explicit,
manual advanced override by the user.
- **Rent / Essence rules:** No rent recovery and no Essence by default.
- **Example asset types:**
- SOL / WSOL special cases
- USDC / USDT / other major assets
- Valuable meme tokens
- NFTs
- LP tokens
- Receipt tokens
- Staked tokens
- Suspicious tokens
- Frozen accounts
- Delegated accounts
- High-value balances
### `UNSUPPORTED`
- **Enum identifier:** `UNSUPPORTED`
- **Meaning:** An account the system **cannot safely reason about** in the MVP.
- **Allowed action(s):** None. These are skipped.
- **Rent / Essence rules:** No rent recovery and no Essence.
- **Example asset types:**
- Token-2022 accounts (in the MVP)
- Unknown token program
- Bad / missing metadata
- Unsupported account layout
- Accounts with extension behavior not yet handled
---
## Safety rules
Reproduced from design doc §7 as a checklist. The classifier and any action
builder must enforce **all** of these. MVP rules:
- [ ] Classic SPL only.
- [ ] Skip Token-2022 by default.
- [ ] Skip NFTs.
- [ ] Skip compressed NFTs.
- [ ] Skip LP tokens.
- [ ] Skip frozen accounts.
- [ ] Skip delegated accounts.
- [ ] Skip known valuable assets.
- [ ] Skip tokens above a user-safe USD threshold.
- [ ] Skip routes with high price impact.
- [ ] Skip routes with stale quotes.
- [ ] Skip unsafe or weird liquidity paths.
- [ ] Simulate all transactions before final signing.
---
## Wording rule
The system must **never** state that a token is safe.
- Forbidden: *"This token is safe."*
- Required: *"This token appears eligible based on current checks."*
This wording is load-bearing: it communicates that eligibility is a snapshot of
current automated checks, not a guarantee about the asset.
---
## Decision flow
How a single account flows from scan to a final category:
1. **Scan** — fetch the token account: owner, ATA address, mint, token program,
raw/UI balance, decimals, metadata if available, token program type, and
frozen/delegated state if available.
2. **Token program check** — if not classic SPL (e.g. Token-2022, unknown
program), classify as `UNSUPPORTED`. Stop.
3. **Account integrity check** — if metadata is bad/missing, the account layout
is unsupported, or extension behavior is unhandled, classify as
`UNSUPPORTED`. Stop.
4. **Protected check** — if the asset is an NFT, compressed NFT, LP token,
receipt token, staked token, major/known-valuable asset, SOL/WSOL special
case, suspicious token, frozen account, delegated account, or a high-value /
over-threshold balance, classify as `PROTECTED_SKIP`. Stop.
5. **Empty check** — if the balance is zero, classify as `EMPTY_CLOSE_ONLY`.
Stop.
6. **Route check** — evaluate a swap route. If a safe route exists and passes all
risk checks (no high price impact, no stale quote, no weird liquidity path,
simulation passes), classify as `TRANSMUTABLE`. Stop.
7. **Fallback** — otherwise the account has a balance with no safe route but may
be burnable junk: classify as `INCINERATE_ONLY`.
At any step where the system cannot safely decide, it falls back to a
non-destructive category — **Unknown means skip.**
```
scan account
├─ not classic SPL? ───────────────────────────────► UNSUPPORTED
├─ bad metadata / layout / unhandled extension? ───► UNSUPPORTED
├─ NFT / cNFT / LP / receipt / staked / major /
│ valuable / SOL-WSOL / suspicious / frozen /
│ delegated / over-threshold? ────────────────────► PROTECTED_SKIP
├─ balance == 0? ──────────────────────────────────► EMPTY_CLOSE_ONLY
├─ safe swap route + passes risk checks? ──────────► TRANSMUTABLE
└─ otherwise (burnable junk, no safe route) ───────► INCINERATE_ONLY
```
---
## Canonical enum
The canonical classification enum and the risk rules live in **`packages/core`**
(shared types and business logic). Apps and the worker import the enum from
there; they must not redefine it.
**The server must recompute classification.** Client-submitted classifications
are never trusted — the backend recomputes classification server-side before
building any transaction (design doc §16). A category arriving from the client is
treated as a hint at most, never as authority for a destructive action.

1
infra/.gitkeep Normal file
View File

@@ -0,0 +1 @@
# infra/ — nginx config, PM2/systemd units, logrotate, backup. TODO (Phase 0).

22
package.json Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "pyre",
"version": "0.1.0",
"private": true,
"description": "PYRE / Prometheus Protocol — Solana wallet-cleanup and ritual meme rebirth protocol (MVP)",
"type": "module",
"packageManager": "pnpm@11.5.0",
"engines": {
"node": ">=22"
},
"scripts": {
"build": "pnpm -r build",
"dev": "pnpm -r --parallel dev",
"typecheck": "pnpm -r typecheck",
"lint": "pnpm -r lint",
"test": "pnpm -r test",
"clean": "pnpm -r exec rm -rf dist .next node_modules/.cache"
},
"devDependencies": {
"typescript": "^5.7.2"
}
}

38
packages/config/README.md Normal file
View File

@@ -0,0 +1,38 @@
# @pyre/config
Shared configuration and environment loading for PYRE.
## Purpose
Per §13: shared config and environment loading. Provides a typed `Env` interface
and a `loadConfig()` loader that maps the variables in the repo-root
`.env.example` into typed config.
## Trust rule
There is intentionally **no** wallet private-key / mnemonic variable here, and
there never will be (§3). All signing happens client-side in the user's wallet.
## Variables (mirrors `.env.example`)
- **Solana** — `SOLANA_RPC_URL`, `SOLANA_RPC_WS_URL`, `SOLANA_CLUSTER`
- **Database** — `DATABASE_URL`
- **Redis** — `REDIS_URL`
- **AI** — `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `IMAGE_GEN_PROVIDER`,
`IMAGE_GEN_API_KEY`
- **App URLs / ports** — `WEB_PORT`, `API_PORT`, `WEB_PUBLIC_URL`,
`API_PUBLIC_URL`
- **Admin / security** — `ADMIN_API_TOKEN`, `RATE_LIMIT_SCAN_PER_MIN`
- **Classification thresholds** — `PROTECTED_USD_THRESHOLD`,
`MAX_PRICE_IMPACT_BPS`, `QUOTE_MAX_AGE_MS`
- **Optional / later phases** — `IPFS_OR_ARWEAVE_ENDPOINT`,
`IPFS_OR_ARWEAVE_TOKEN`, `PUMPFUN_CREATOR_WALLET_PUBKEY` (public key only)
## Status
**Skeleton.** Defines `Env`; `loadConfig()` is a stub.
## TODO
- Implement `loadConfig()` — read `process.env`, validate/coerce, apply defaults,
fail fast on missing required values. Never hardcode secrets.

View File

@@ -0,0 +1,17 @@
{
"name": "@pyre/config",
"version": "0.1.0",
"private": true,
"type": "module",
"main": "./src/index.ts",
"types": "./src/index.ts",
"scripts": {
"build": "tsc -p tsconfig.json",
"typecheck": "tsc --noEmit",
"lint": "echo \"lint: ok (placeholder)\"",
"test": "echo \"test: ok (placeholder)\""
},
"devDependencies": {
"typescript": "^5.7.2"
}
}

View File

@@ -0,0 +1,72 @@
/**
* @pyre/config — shared config & environment loading (SKELETON).
*
* Responsibilities (§13): shared config and environment loading. Variables mirror
* `.env.example` at the repo root.
*
* TRUST RULE (§3): there is intentionally NO wallet private-key / mnemonic
* variable here, and there never will be. All signing happens client-side.
*
* Do NOT hardcode secrets — values come from the process environment at runtime.
*/
export type SolanaCluster = "mainnet-beta" | "devnet" | "testnet";
/**
* Typed view of the supported environment variables.
* Mirrors `.env.example` (sans the deliberately-absent private-key var).
*/
export interface Env {
// ---- Solana ----
solanaRpcUrl: string;
solanaRpcWsUrl?: string;
solanaCluster: SolanaCluster;
// ---- Database (PostgreSQL) ----
databaseUrl: string;
// ---- Redis (queues, cache, rate limiting) ----
redisUrl: string;
// ---- AI services (Prometheus) ----
anthropicApiKey?: string;
openaiApiKey?: string;
/** e.g. "openai" | "stability" | "replicate". */
imageGenProvider?: string;
imageGenApiKey?: string;
// ---- App URLs / ports ----
webPort: number;
apiPort: number;
webPublicUrl: string;
apiPublicUrl: string;
// ---- Admin / security ----
adminApiToken?: string;
rateLimitScanPerMin: number;
// ---- Classification safety thresholds ----
/** Skip tokens valued above this (USD). */
protectedUsdThreshold: number;
/** Skip swap routes above this price impact (basis points). */
maxPriceImpactBps: number;
/** Skip stale quotes older than this (ms). */
quoteMaxAgeMs: number;
// ---- Optional: metadata / launch (later phases) ----
ipfsOrArweaveEndpoint?: string;
ipfsOrArweaveToken?: string;
/** Public key ONLY — operator signs Pump.fun launches manually in the MVP. */
pumpfunCreatorWalletPubkey?: string;
}
/**
* Load and validate configuration from the process environment.
*
* TODO: read from `process.env` (mapping the variables in `.env.example`),
* validate/coerce types, apply defaults, and fail fast on missing required
* values. Never hardcode secrets. There is intentionally no private-key var.
*/
export function loadConfig(): Env {
throw new Error("not implemented");
}

View File

@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}

32
packages/core/README.md Normal file
View File

@@ -0,0 +1,32 @@
# @pyre/core
Shared types and business logic for PYRE / Prometheus Protocol.
## Purpose
The canonical home for cross-cutting type definitions and (eventually) pure
business logic shared by `apps/*` and the other `packages/*`. Per §13 its
responsibilities are:
- **Classification enums** — `TokenClassification` (§6).
- **Risk rules** — conservative safety-rule types/constants (§7). _Placeholder._
- **Shared DTOs** — request/response shapes for the HTTP API (§14).
- **Receipt schema** — `CleanupReceipt` (§8, §15).
- **Prometheus I/O schema** — `PrometheusInput` / `PrometheusOutput` (§9).
This package carries **real type definitions** but **no application logic** in
the skeleton.
## Modules
- `src/classification.ts``TokenClassification` enum.
- `src/dto.ts` — API request/response DTOs.
- `src/receipt.ts` — cleanup receipt schema.
- `src/prometheus.ts` — Prometheus meta-mixer input/output.
- `src/risk.ts` — risk-rule placeholder.
## TODO
- Define concrete risk-rule identifiers, threshold shapes, and pure evaluators.
- Tighten DTO shapes flagged `TODO` once the scan/classify/build pipeline lands.
- Define the concrete token `metadata` JSON shape used by receipts and Prometheus.

View File

@@ -0,0 +1,17 @@
{
"name": "@pyre/core",
"version": "0.1.0",
"private": true,
"type": "module",
"main": "./src/index.ts",
"types": "./src/index.ts",
"scripts": {
"build": "tsc -p tsconfig.json",
"typecheck": "tsc --noEmit",
"lint": "echo \"lint: ok (placeholder)\"",
"test": "echo \"test: ok (placeholder)\""
},
"devDependencies": {
"typescript": "^5.7.2"
}
}

View File

@@ -0,0 +1,45 @@
/**
* Conservative token-account classification categories.
*
* See §6 (Token Classification) and §7 (Token Safety Rules) of
* `docs/PYRE_MVP_DESIGN.md`. The classifier must be conservative — it must never
* assert that a token is "safe", only that it "appears eligible based on current
* checks". Anything that cannot be reasoned about safely defaults to
* `PROTECTED_SKIP` / `UNSUPPORTED` ("Unknown means skip").
*/
export enum TokenClassification {
/**
* Zero balance; the associated token account (ATA) can be closed.
* Action: close the ATA and return the recovered rent to the user wallet.
*/
EMPTY_CLOSE_ONLY = "EMPTY_CLOSE_ONLY",
/**
* Has a balance but no safe swap route; the balance may, however, be burnable.
* Action: the user may burn the balance to zero; if the account then becomes
* empty it can be closed, and recovered rent returns to the user.
*/
INCINERATE_ONLY = "INCINERATE_ONLY",
/**
* Has a safe swap route and passes risk checks.
* Action: the user may swap the token into SOL; net swapped SOL may become
* Essence ONLY if the user explicitly opts in.
*/
TRANSMUTABLE = "TRANSMUTABLE",
/**
* Not touched by default. Examples: SOL/WSOL special cases, USDC/USDT/major
* assets, valuable meme tokens, NFTs, LP tokens, receipt tokens, staked
* tokens, suspicious tokens, frozen accounts, delegated accounts, and
* high-value balances. Requires explicit manual opt-in to act on.
*/
PROTECTED_SKIP = "PROTECTED_SKIP",
/**
* The system cannot safely reason about the account. Examples: Token-2022 in
* the MVP, unknown token program, bad metadata, unsupported account layout, or
* accounts with extension behavior not yet handled.
*/
UNSUPPORTED = "UNSUPPORTED",
}

172
packages/core/src/dto.ts Normal file
View File

@@ -0,0 +1,172 @@
/**
* Shared API DTOs for the PYRE HTTP API.
*
* Shapes are derived from §14 (API Design) of `docs/PYRE_MVP_DESIGN.md`.
*
* NOTE: lamport amounts are represented as `string` (not `number`) to avoid
* precision loss with large u64 values, matching the design doc's JSON shapes.
*
* TODO: several shapes below are approximate and will be tightened once the
* scan/classify/build pipeline is implemented. Approximations are flagged inline.
*/
import type { TokenClassification } from "./classification.js";
// ---------------------------------------------------------------------------
// POST /api/scan
// ---------------------------------------------------------------------------
export interface ScanRequest {
/** Wallet public key (base58). */
wallet: string;
}
export interface ScanSummary {
totalAccounts: number;
emptyCloseOnly: number;
incinerateOnly: number;
transmutable: number;
protectedSkip: number;
unsupported: number;
/** Total estimated recoverable rent across closeable accounts, in lamports. */
estimatedRentLamports: string;
}
export interface TokenAccountDto {
/** Associated token account address (base58). */
ata: string;
/** Owner wallet (base58). */
owner: string;
/** Token mint (base58). */
mint: string;
/** Owning token program (base58). Classic SPL only in the MVP. */
tokenProgram: string;
/** Raw on-chain balance (u64 as string). */
rawBalance: string;
/** Human-readable balance (raw / 10^decimals). */
uiBalance: number;
decimals: number;
/** Token symbol, if metadata is available. */
symbol?: string;
/** Token name, if metadata is available. */
name?: string;
classification: TokenClassification;
/** Human-readable warnings surfaced to the user (e.g. "frozen account"). */
warnings: string[];
/** Estimated rent recoverable by closing this account, in lamports. */
estimatedRentLamports: string;
/** Whether the account is frozen, if known. TODO: confirm availability. */
frozen?: boolean;
/** Whether the account is delegated, if known. TODO: confirm availability. */
delegated?: boolean;
}
export interface ScanResponse {
/** UUID of the persisted scan. */
scanId: string;
wallet: string;
summary: ScanSummary;
accounts: TokenAccountDto[];
}
// ---------------------------------------------------------------------------
// POST /api/build/close-empty
// ---------------------------------------------------------------------------
export interface BuildCloseEmptyRequest {
wallet: string;
/** ATA addresses to close (must be EMPTY_CLOSE_ONLY). */
accountAddresses: string[];
}
export interface BuildCloseEmptyPreview {
accountsToClose: string[];
estimatedRentReturnedLamports: string;
/** Destination for recovered rent — must default to the user's own wallet. */
rentDestination: string;
}
export interface BuildCloseEmptyResponse {
/** Unsigned transaction, base64-encoded. Signed client-side only. */
transactionBase64: string;
preview: BuildCloseEmptyPreview;
}
// ---------------------------------------------------------------------------
// POST /api/build/burn
// ---------------------------------------------------------------------------
export interface BurnItem {
/** Token account holding the balance to burn (base58). */
tokenAccount: string;
/** Mint of the token being burned (base58). */
mint: string;
/** Raw amount to burn (u64 as string). */
amount: string;
}
export interface BuildBurnRequest {
wallet: string;
items: BurnItem[];
}
export interface BuildBurnPreview {
tokensToBurn: BurnItem[];
/** Accounts that may become closeable once their balance reaches zero. */
accountsPotentiallyClosable: string[];
/** TODO: include estimated rent and fees once the builder is implemented. */
estimatedRentReturnedLamports?: string;
}
export interface BuildBurnResponse {
/** Unsigned transaction, base64-encoded. Signed client-side only. */
transactionBase64: string;
preview: BuildBurnPreview;
}
// ---------------------------------------------------------------------------
// POST /api/receipt
// ---------------------------------------------------------------------------
export interface ReceiptRequest {
wallet: string;
/** Confirmed transaction signature. */
txSignature: string;
/** UUID of the originating scan. */
scanId: string;
}
export interface ReceiptResponse {
receiptId: string;
txSignature: string;
rentReturnedLamports: string;
/** Addresses of accounts that were closed. */
closedAccounts: string[];
/** Mints (or token accounts) that were burned. TODO: confirm element shape. */
burnedTokens: string[];
/** Accounts intentionally skipped. TODO: confirm element shape. */
skippedTokens: string[];
}
// ---------------------------------------------------------------------------
// POST /api/prometheus/generate
// ---------------------------------------------------------------------------
export interface PrometheusGenerateRequest {
receiptId: string;
/** Chaos factor 0..1 controlling mutation strength. */
chaos: number;
/** Optional manual operator theme seed. */
operatorSeed?: string;
}
export interface PrometheusGenerateResponse {
generationId: string;
spawnName: string;
ticker: string;
lore: string;
imagePrompt: string;
/** Token metadata JSON blob. TODO: define concrete metadata shape. */
metadata: Record<string, unknown>;
/** Safety/compliance flags raised during generation. */
riskFlags: string[];
}

View File

@@ -0,0 +1,5 @@
export * from "./classification.js";
export * from "./dto.js";
export * from "./receipt.js";
export * from "./prometheus.js";
export * from "./risk.js";

View File

@@ -0,0 +1,43 @@
/**
* Prometheus AI meta-mixer I/O schema.
*
* Input/output shapes from §9 (Prometheus AI Meta Mixer) of
* `docs/PYRE_MVP_DESIGN.md`. Prometheus generates Spawn *identity* only — it
* never controls funds.
*/
/** A token contributing to a Spawn, summarized from a cleanup receipt. */
export interface PrometheusTokenRef {
mint: string;
symbol?: string;
name?: string;
}
export interface PrometheusInput {
burnedTokens: PrometheusTokenRef[];
transmutedTokens: PrometheusTokenRef[];
tokenSymbols: string[];
tokenNames: string[];
metadataDescriptions: string[];
/** Dominant thematic archetypes inferred from the inputs. */
dominantArchetypes: string[];
/** Chaos factor 0..1 controlling mutation strength. */
chaosFactor: number;
/** Optional manual operator theme seed. */
manualThemeSeed?: string;
}
export interface PrometheusOutput {
spawnName: string;
spawnTicker: string;
spawnLore: string;
spawnTagline: string;
spawnDescription: string;
imagePrompt: string;
/** Token metadata JSON blob. TODO: define concrete metadata shape. */
metadataJson: Record<string, unknown>;
/** Marketing/launch copy. */
launchCopy: string;
/** Safety/compliance flags raised during generation. */
riskFlags: string[];
}

View File

@@ -0,0 +1,60 @@
/**
* Cleanup receipt schema.
*
* Models the receipt produced after a confirmed burner transaction. Fields are
* drawn from §8 (Burner Transaction Flow — step 8) and §15 (cleanup_receipts
* table) of `docs/PYRE_MVP_DESIGN.md`.
*
* This is the canonical, enriched receipt persisted as `receipt_json`; the API
* surfaces a subset via `ReceiptResponse` in `dto.ts`.
*/
export interface ClosedAccountEntry {
/** ATA address that was closed (base58). */
ata: string;
mint: string;
/** Rent reclaimed from closing this account, in lamports. */
rentLamports: string;
}
export interface BurnedTokenEntry {
tokenAccount: string;
mint: string;
/** Raw amount burned (u64 as string). */
amount: string;
symbol?: string;
name?: string;
}
export interface SkippedTokenEntry {
ata: string;
mint: string;
/** Why this account was skipped (classification + warnings). */
reason: string;
}
export interface CleanupReceipt {
/** Receipt UUID. */
receiptId: string;
/** Originating scan UUID. */
scanId: string;
/** Owner wallet (base58). */
wallet: string;
/** Confirmed transaction signature. */
txSignature: string;
/** Total rent returned to the user, in lamports. */
rentReturnedLamports: string;
/** Destination wallet for recovered rent — defaults to the user's wallet. */
rentDestination: string;
closedAccounts: ClosedAccountEntry[];
burnedTokens: BurnedTokenEntry[];
skippedTokens: SkippedTokenEntry[];
/** Network/transaction fees paid, in lamports. */
feeLamports?: string;
/** Warnings shown to the user before signing. */
warnings: string[];
/** ISO-8601 timestamp the receipt was finalized. */
createdAt: string;
/** Optional shareable receipt image URL. */
shareImageUrl?: string;
}

15
packages/core/src/risk.ts Normal file
View File

@@ -0,0 +1,15 @@
/**
* Risk-rule types and constants (placeholder).
*
* The conservative safety rules from §7 (Token Safety Rules) live here once the
* classifier is implemented. Thresholds are operator-tunable via `@pyre/config`
* (e.g. PROTECTED_USD_THRESHOLD, MAX_PRICE_IMPACT_BPS, QUOTE_MAX_AGE_MS).
*
* Guiding principle: the system must never assert a token is "safe" — only that
* it "appears eligible based on current checks". Unknown means skip.
*
* TODO: define risk-rule identifiers, a RiskRuleResult type, threshold config
* shape, and the (pure) evaluation function signatures. No implementation yet.
*/
export {};

View File

@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}

44
packages/db/README.md Normal file
View File

@@ -0,0 +1,44 @@
# @pyre/db
Database schema, migrations, and table definitions for PYRE (PostgreSQL).
## Purpose
Per §13: the schema, migrations, and table definitions. Uses `pg` for
connectivity. Connection details come from `DATABASE_URL` via `@pyre/config`
**never** hardcode credentials.
## Tables (§15)
### Initial MVP tables
- `wallet_scans` — id, wallet, status, created_at, completed_at, summary_json
- `token_accounts` — id, scan_id, wallet, ata, mint, token_program, raw_balance,
ui_balance, decimals, symbol, name, classification, warnings_json,
estimated_rent_lamports, created_at
- `cleanup_receipts` — id, wallet, scan_id, tx_signature, rent_returned_lamports,
closed_accounts_count, burned_tokens_count, status, created_at, receipt_json
- `prometheus_generations` — id, receipt_id, input_json, output_json, status,
risk_flags_json, created_at, approved_at, rejected_at
- `spawn_records` — id, generation_id, spawn_name, ticker, mint, metadata_uri,
pumpfun_url, launch_tx, status, created_at
### Future tables
- `token_classifications`
- `burn_events`
- `close_account_events`
- `spawn_candidates`
- `system_events`
## Status
**Skeleton.** Exports table-name constants and a connection-factory stub. No
queries, no schema DDL, no migrations yet.
## TODO
- Implement the `createPool()` connection factory (read `DATABASE_URL` via
`@pyre/config`).
- Add SQL migrations under `migrations/` and a migration runner.
- Add typed table definitions and a query layer.

View File

View File

@@ -0,0 +1,15 @@
# Migrations
SQL migrations for the PYRE PostgreSQL database.
**Empty for now** (skeleton). Migration files and a runner will be added here.
## Convention (TODO)
- One forward migration per file, ordered/timestamped (e.g.
`0001_init.sql`, `0002_<change>.sql`).
- The first migration creates the initial MVP tables listed in the package
README (§15): `wallet_scans`, `token_accounts`, `cleanup_receipts`,
`prometheus_generations`, `spawn_records`.
- A migration runner (in `@pyre/db`) applies pending migrations against
`DATABASE_URL`.

22
packages/db/package.json Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "@pyre/db",
"version": "0.1.0",
"private": true,
"type": "module",
"main": "./src/index.ts",
"types": "./src/index.ts",
"scripts": {
"build": "tsc -p tsconfig.json",
"typecheck": "tsc --noEmit",
"lint": "echo \"lint: ok (placeholder)\"",
"test": "echo \"test: ok (placeholder)\""
},
"dependencies": {
"@pyre/config": "workspace:*",
"pg": "^8.13.1"
},
"devDependencies": {
"@types/pg": "^8.11.10",
"typescript": "^5.7.2"
}
}

44
packages/db/src/index.ts Normal file
View File

@@ -0,0 +1,44 @@
/**
* @pyre/db — database schema, migrations, and table definitions (SKELETON).
*
* Responsibilities (§13): database schema, migrations, table definitions.
* Schema reference: §15 (MVP Database Schema) of `docs/PYRE_MVP_DESIGN.md`.
*
* No queries are implemented here yet — only table-name constants and a
* connection-factory stub.
*/
import type { Pool } from "pg";
/**
* Canonical table names. Centralized so query/migration code references a single
* source of truth.
*/
export const TABLES = {
// Initial MVP tables (§15)
WALLET_SCANS: "wallet_scans",
TOKEN_ACCOUNTS: "token_accounts",
CLEANUP_RECEIPTS: "cleanup_receipts",
PROMETHEUS_GENERATIONS: "prometheus_generations",
SPAWN_RECORDS: "spawn_records",
// Future tables (§15)
TOKEN_CLASSIFICATIONS: "token_classifications",
BURN_EVENTS: "burn_events",
CLOSE_ACCOUNT_EVENTS: "close_account_events",
SPAWN_CANDIDATES: "spawn_candidates",
SYSTEM_EVENTS: "system_events",
} as const;
export type TableName = (typeof TABLES)[keyof typeof TABLES];
/**
* Connection-factory stub.
*
* TODO: create and cache a `pg` Pool from DATABASE_URL (resolved via
* `@pyre/config` — never hardcode credentials). Then add a migration runner and
* typed table-definition / query layer. No queries are implemented yet.
*/
export function createPool(): Pool {
// TODO: const { databaseUrl } = loadConfig(); return new Pool({ connectionString: databaseUrl });
throw new Error("not implemented");
}

View File

@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}

View File

@@ -0,0 +1,36 @@
# @pyre/prometheus
AI generation logic for the Prometheus meta mixer.
## Purpose
Generates Spawn **identity** (name, ticker, lore, image prompt, metadata) from
cleanup receipts. Per §13 its responsibilities are:
- Prompt templates.
- Meta mixer.
- Output parser.
- Safety checks.
- Image-prompt generator.
See §9 (meta mixer) and §10 (Pump.fun creator workflow). Prometheus never
controls funds; it only produces creative identity for **manual, human-reviewed**
launch in the MVP.
## Design rules
- Meta influence is probabilistic, not deterministic.
- Produce inspired mutations, not direct clones — reject exact copyrighted or
existing meme identities.
## Status
**Stubs only.** Every exported function throws `Error("not implemented")`.
## TODO
- Implement `buildPrompt`, `runMetaMixer`, `parseOutput`, `runSafetyChecks`,
`generateImagePrompt`.
- The AI client (Anthropic / OpenAI / image-gen provider) is configured via
`@pyre/config` and injected here. This package adds **no** SDK dependencies of
its own.

View File

@@ -0,0 +1,20 @@
{
"name": "@pyre/prometheus",
"version": "0.1.0",
"private": true,
"type": "module",
"main": "./src/index.ts",
"types": "./src/index.ts",
"scripts": {
"build": "tsc -p tsconfig.json",
"typecheck": "tsc --noEmit",
"lint": "echo \"lint: ok (placeholder)\"",
"test": "echo \"test: ok (placeholder)\""
},
"dependencies": {
"@pyre/core": "workspace:*"
},
"devDependencies": {
"typescript": "^5.7.2"
}
}

View File

@@ -0,0 +1,72 @@
/**
* @pyre/prometheus — AI generation logic (STUBS ONLY).
*
* Responsibilities (§13): prompt templates, the meta mixer, output parser,
* safety checks, and the image-prompt generator. See §9 (Prometheus AI Meta
* Mixer) and §10 (Pump.fun Creator Workflow) of `docs/PYRE_MVP_DESIGN.md`.
*
* Design notes:
* - Prometheus generates Spawn *identity* only — it never controls funds.
* - Meta influence is probabilistic, not deterministic.
* - Do not allow users to force exact copyrighted/existing meme identities;
* produce inspired mutations, not direct clones.
*
* TODO: the AI client (Anthropic / OpenAI / image-gen provider) is configured
* via `@pyre/config` and injected here — this package adds NO SDK dependencies
* of its own. Wire the client through function parameters or a small interface.
*
* Nothing here is implemented yet — every function throws "not implemented".
*/
import type { PrometheusInput, PrometheusOutput } from "@pyre/core";
const NOT_IMPLEMENTED = "not implemented";
/**
* Build the text-generation prompt from mixer input.
*
* TODO: apply prompt templates and the probabilistic meta-influence weighting
* (burned archetypes / Essence themes / chaos mutation / operator seed).
*/
export function buildPrompt(_input: PrometheusInput): string {
throw new Error(NOT_IMPLEMENTED);
}
/**
* Run the meta mixer end-to-end: build prompt, call the AI client, parse, and
* run safety checks, producing a Spawn package.
*
* TODO: orchestrate buildPrompt -> AI client -> parseOutput -> runSafetyChecks.
* The AI client is injected (configured via @pyre/config).
*/
export function runMetaMixer(_input: PrometheusInput): Promise<PrometheusOutput> {
throw new Error(NOT_IMPLEMENTED);
}
/**
* Parse a raw model response into a structured `PrometheusOutput`.
*
* TODO: validate/normalize the model JSON into the output schema.
*/
export function parseOutput(_raw: string): PrometheusOutput {
throw new Error(NOT_IMPLEMENTED);
}
/**
* Run safety/compliance checks over generated output.
*
* TODO: moderation + copyright/clone guards; return risk flags. Must reject
* attempts to clone exact copyrighted or existing meme identities.
*/
export function runSafetyChecks(_output: PrometheusOutput): Promise<string[]> {
throw new Error(NOT_IMPLEMENTED);
}
/**
* Generate an image prompt for the Spawn artwork.
*
* TODO: derive an image prompt from the Spawn identity, honoring the same
* anti-clone safety rules.
*/
export function generateImagePrompt(_output: PrometheusOutput): string {
throw new Error(NOT_IMPLEMENTED);
}

View File

@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}

33
packages/solana/README.md Normal file
View File

@@ -0,0 +1,33 @@
# @pyre/solana
Solana transaction helpers for PYRE.
## Purpose
Token-account reading and **unsigned** transaction construction for the burner
flow. Per §13 its responsibilities are:
- Token-account parsing.
- Close-account transaction builder.
- Burn transaction builder.
- Simulation helpers.
- Transaction decoder (for preview matching).
## Trust rules (load-bearing)
- PYRE never holds private keys — this package builds **unsigned** transactions;
signing happens client-side in the user's wallet.
- Recovered ATA rent defaults to the user's own wallet.
- Always simulate, then **decode** and match against the user-facing preview
before requesting a signature.
- Classic SPL only in the MVP. Skip Token-2022, NFTs, and unsupported layouts.
## Status
**Stubs only.** Every exported function throws `Error("not implemented")`.
## TODO
- Implement `parseTokenAccounts`, `buildCloseEmptyAccountsTx`, `buildBurnTx`,
`simulateTransaction`, and `decodeTransaction`.
- Wire classification through `@pyre/core`.

View File

@@ -0,0 +1,22 @@
{
"name": "@pyre/solana",
"version": "0.1.0",
"private": true,
"type": "module",
"main": "./src/index.ts",
"types": "./src/index.ts",
"scripts": {
"build": "tsc -p tsconfig.json",
"typecheck": "tsc --noEmit",
"lint": "echo \"lint: ok (placeholder)\"",
"test": "echo \"test: ok (placeholder)\""
},
"dependencies": {
"@pyre/core": "workspace:*",
"@solana/web3.js": "^1.98.0",
"@solana/spl-token": "^0.4.9"
},
"devDependencies": {
"typescript": "^5.7.2"
}
}

View File

@@ -0,0 +1,94 @@
/**
* @pyre/solana — Solana transaction helpers (STUBS ONLY).
*
* Responsibilities (§13): token-account parsing, close-account tx builder, burn
* tx builder, simulation helpers, and a transaction decoder.
*
* IMPORTANT (trust rules, §3/§7/§16):
* - PYRE never holds private keys; these helpers build **unsigned** transactions
* only. Signing happens client-side in the user's wallet.
* - Recovered ATA rent must default to the user's own wallet.
* - Every transaction must be simulated and **decoded**, then matched against the
* preview shown to the user before any signature is requested.
* - Classic SPL only in the MVP. Skip Token-2022 / NFTs / unsupported layouts.
*
* Nothing here is implemented yet — every function throws "not implemented".
*/
import type { Connection, PublicKey } from "@solana/web3.js";
import type {
TokenAccountDto,
BuildCloseEmptyPreview,
BuildBurnPreview,
BurnItem,
} from "@pyre/core";
const NOT_IMPLEMENTED = "not implemented";
/**
* Parse a wallet's SPL token accounts into classified DTOs.
*
* TODO: fetch token accounts via RPC, decode account state (balance, decimals,
* frozen/delegated, token program), resolve metadata, and hand off to the
* classifier in `@pyre/core`. Classic SPL only.
*/
export function parseTokenAccounts(
_connection: Connection,
_wallet: PublicKey,
): Promise<TokenAccountDto[]> {
throw new Error(NOT_IMPLEMENTED);
}
/**
* Build an UNSIGNED transaction that closes the given empty ATAs, returning rent
* to the user wallet.
*
* TODO: assemble CloseAccount instructions, set fee payer + rent destination to
* the user, return a base64 transaction plus a matching preview.
*/
export function buildCloseEmptyAccountsTx(
_connection: Connection,
_wallet: PublicKey,
_accountAddresses: PublicKey[],
): Promise<{ transactionBase64: string; preview: BuildCloseEmptyPreview }> {
throw new Error(NOT_IMPLEMENTED);
}
/**
* Build an UNSIGNED transaction that burns the given token balances (optionally
* closing accounts that become empty).
*
* TODO: assemble Burn (and optional CloseAccount) instructions, return a base64
* transaction plus a matching preview.
*/
export function buildBurnTx(
_connection: Connection,
_wallet: PublicKey,
_items: BurnItem[],
): Promise<{ transactionBase64: string; preview: BuildBurnPreview }> {
throw new Error(NOT_IMPLEMENTED);
}
/**
* Simulate a transaction before signing.
*
* TODO: run `connection.simulateTransaction`, surface logs/errors, and confirm
* the simulation succeeds. All transactions must be simulated before signing.
*/
export function simulateTransaction(
_connection: Connection,
_transactionBase64: string,
): Promise<unknown> {
throw new Error(NOT_IMPLEMENTED);
}
/**
* Decode an unsigned transaction so its contents can be matched against the
* preview shown to the user (accounts to close, tokens to burn, rent amount,
* rent destination, fees, warnings).
*
* TODO: deserialize the transaction, decode SPL instructions, and return a
* structured, human-comparable summary.
*/
export function decodeTransaction(_transactionBase64: string): unknown {
throw new Error(NOT_IMPLEMENTED);
}

View File

@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}

10474
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

19
pnpm-workspace.yaml Normal file
View File

@@ -0,0 +1,19 @@
packages:
- "apps/*"
- "packages/*"
# Postinstall build-script approvals (pnpm). Only packages that ship prebuilt
# binaries are allowed; the rest are optional native accelerations with pure-JS
# fallbacks and are skipped to avoid needing a C/C++ toolchain on the server.
allowBuilds:
esbuild: true # prebuilt binary; used by tsx for dev
sharp: true # prebuilt binary; Next.js image optimization
'@stellar/stellar-sdk': false
bigint-buffer: false
blake-hash: false
bufferutil: false
msgpackr-extract: false
protobufjs: false
tiny-secp256k1: false
usb: false # ledger hardware-wallet native module; not needed for MVP
utf-8-validate: false

27
preview.html Normal file
View File

@@ -0,0 +1,27 @@
<!DOCTYPE html>
<!--
PYRE — static receipt/UI preview placeholder.
Per docs/PYRE_MVP_DESIGN.md §13. Used for quick visual iteration on the
"beautiful receipt experience" before wiring the Next.js app (apps/web).
TODO: replace with a real receipt mock.
-->
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>PYRE — Preview</title>
<style>
body { background:#0a0a0a; color:#f5f5f5; font-family:ui-monospace,monospace;
display:grid; place-items:center; min-height:100vh; margin:0; }
.pyre { text-align:center; }
.ember { color:#ff5a1f; letter-spacing:.3em; }
</style>
</head>
<body>
<div class="pyre">
<h1 class="ember">PYRE</h1>
<p>Burn the dead. Feed the PYRE. Claim the Spawn.</p>
<p><small>Preview placeholder — see docs/PYRE_MVP_DESIGN.md</small></p>
</div>
</body>
</html>

View File

@@ -0,0 +1,24 @@
# programs/pyre-core
**Future** Anchor (Solana) program for trust-critical, on-chain accounting.
> **Not needed for the first burner MVP (v0.1v0.4).** This directory is a
> placeholder. The PYRE Core Program lands in **MVP v1.0** (see
> [`docs/PYRE_MVP_DESIGN.md`](../../docs/PYRE_MVP_DESIGN.md) §5, §18 Phase 7).
## Planned program responsibilities (v1.0)
- create round
- accept Essence
- hold Essence vault
- record contribution receipts (receipt PDA)
- lock round
- register Spawn mint
- open claims
- distribute Spawn pro rata
- support refunds for failed rounds
- prevent double claims
Until on-chain custody exists: do **not** call contributions a "deposit" and do
**not** promise claims. Off-chain Essence accounting (Phase 6) stays explicitly
experimental.

1
scripts/.gitkeep Normal file
View File

@@ -0,0 +1 @@
# scripts/ — operational scripts (backup, deploy, db migrate). TODO.

24
tsconfig.base.json Normal file
View File

@@ -0,0 +1,24 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022"],
"module": "ESNext",
"moduleResolution": "Bundler",
"moduleDetection": "force",
"verbatimModuleSyntax": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"isolatedModules": true,
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"noFallthroughCasesInSwitch": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"exclude": ["node_modules", "dist", ".next"]
}