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:
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"]
|
||||
}
|
||||
Reference in New Issue
Block a user