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:
49
.env.example
Normal file
49
.env.example
Normal 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
38
.gitignore
vendored
Normal 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
5
.npmrc
Normal 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
2
.serena/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/cache
|
||||
/project.local.yml
|
||||
23
.serena/memories/codebase_structure.md
Normal file
23
.serena/memories/codebase_structure.md
Normal 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.
|
||||
21
.serena/memories/project_overview.md
Normal file
21
.serena/memories/project_overview.md
Normal 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`.
|
||||
23
.serena/memories/suggested_commands_and_conventions.md
Normal file
23
.serena/memories/suggested_commands_and_conventions.md
Normal 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
133
.serena/project.yml
Normal 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 read‑only.
|
||||
# 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
164
CLAUDE.md
Normal 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.
|
||||
92
README.md
92
README.md
@@ -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
38
apps/api/README.md
Normal 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
28
apps/api/package.json
Normal 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
57
apps/api/src/index.ts
Normal 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
9
apps/api/tsconfig.json
Normal 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
43
apps/web/README.md
Normal 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
34
apps/web/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
8
apps/web/postcss.config.mjs
Normal file
8
apps/web/postcss.config.mjs
Normal file
@@ -0,0 +1,8 @@
|
||||
/** Tailwind CSS v4 PostCSS setup. */
|
||||
const config = {
|
||||
plugins: {
|
||||
"@tailwindcss/postcss": {},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
3
apps/web/src/app/globals.css
Normal file
3
apps/web/src/app/globals.css
Normal file
@@ -0,0 +1,3 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
/* PYRE global styles. TODO: theme tokens (ember palette) once UI work begins. */
|
||||
17
apps/web/src/app/layout.tsx
Normal file
17
apps/web/src/app/layout.tsx
Normal 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
20
apps/web/src/app/page.tsx
Normal 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
3
apps/web/src/globals.d.ts
vendored
Normal 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
15
apps/web/tsconfig.json
Normal 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
36
apps/worker/README.md
Normal 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
27
apps/worker/package.json
Normal 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
26
apps/worker/src/index.ts
Normal 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();
|
||||
9
apps/worker/tsconfig.json
Normal file
9
apps/worker/tsconfig.json
Normal 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
489
docs/ARCHITECTURE.md
Normal 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 6–7):
|
||||
|
||||
- `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
559
docs/PYRE_MVP_DESIGN.md
Normal 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
128
docs/SECURITY.md
Normal 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.
|
||||
186
docs/TOKEN_CLASSIFICATION.md
Normal file
186
docs/TOKEN_CLASSIFICATION.md
Normal 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
1
infra/.gitkeep
Normal file
@@ -0,0 +1 @@
|
||||
# infra/ — nginx config, PM2/systemd units, logrotate, backup. TODO (Phase 0).
|
||||
22
package.json
Normal file
22
package.json
Normal 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
38
packages/config/README.md
Normal 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.
|
||||
17
packages/config/package.json
Normal file
17
packages/config/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
72
packages/config/src/index.ts
Normal file
72
packages/config/src/index.ts
Normal 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");
|
||||
}
|
||||
8
packages/config/tsconfig.json
Normal file
8
packages/config/tsconfig.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
32
packages/core/README.md
Normal file
32
packages/core/README.md
Normal 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.
|
||||
17
packages/core/package.json
Normal file
17
packages/core/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
45
packages/core/src/classification.ts
Normal file
45
packages/core/src/classification.ts
Normal 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
172
packages/core/src/dto.ts
Normal 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[];
|
||||
}
|
||||
5
packages/core/src/index.ts
Normal file
5
packages/core/src/index.ts
Normal 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";
|
||||
43
packages/core/src/prometheus.ts
Normal file
43
packages/core/src/prometheus.ts
Normal 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[];
|
||||
}
|
||||
60
packages/core/src/receipt.ts
Normal file
60
packages/core/src/receipt.ts
Normal 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
15
packages/core/src/risk.ts
Normal 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 {};
|
||||
8
packages/core/tsconfig.json
Normal file
8
packages/core/tsconfig.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
44
packages/db/README.md
Normal file
44
packages/db/README.md
Normal 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.
|
||||
0
packages/db/migrations/.gitkeep
Normal file
0
packages/db/migrations/.gitkeep
Normal file
15
packages/db/migrations/README.md
Normal file
15
packages/db/migrations/README.md
Normal 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
22
packages/db/package.json
Normal 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
44
packages/db/src/index.ts
Normal 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");
|
||||
}
|
||||
8
packages/db/tsconfig.json
Normal file
8
packages/db/tsconfig.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
36
packages/prometheus/README.md
Normal file
36
packages/prometheus/README.md
Normal 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.
|
||||
20
packages/prometheus/package.json
Normal file
20
packages/prometheus/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
72
packages/prometheus/src/index.ts
Normal file
72
packages/prometheus/src/index.ts
Normal 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);
|
||||
}
|
||||
8
packages/prometheus/tsconfig.json
Normal file
8
packages/prometheus/tsconfig.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
33
packages/solana/README.md
Normal file
33
packages/solana/README.md
Normal 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`.
|
||||
22
packages/solana/package.json
Normal file
22
packages/solana/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
94
packages/solana/src/index.ts
Normal file
94
packages/solana/src/index.ts
Normal 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);
|
||||
}
|
||||
8
packages/solana/tsconfig.json
Normal file
8
packages/solana/tsconfig.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
10474
pnpm-lock.yaml
generated
Normal file
10474
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
19
pnpm-workspace.yaml
Normal file
19
pnpm-workspace.yaml
Normal 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
27
preview.html
Normal 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>
|
||||
24
programs/pyre-core/README.md
Normal file
24
programs/pyre-core/README.md
Normal 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.1–v0.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
1
scripts/.gitkeep
Normal file
@@ -0,0 +1 @@
|
||||
# scripts/ — operational scripts (backup, deploy, db migrate). TODO.
|
||||
24
tsconfig.base.json
Normal file
24
tsconfig.base.json
Normal 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"]
|
||||
}
|
||||
Reference in New Issue
Block a user