diff --git a/docs/PYRE_MVP_DESIGN.md b/docs/PYRE_MVP_DESIGN.md index 435de4c..438a7b3 100644 --- a/docs/PYRE_MVP_DESIGN.md +++ b/docs/PYRE_MVP_DESIGN.md @@ -5,6 +5,13 @@ **Tagline:** *Burn the dead. Feed the PYRE. Claim the Spawn.* +> **Revision note — Rev 2 (2026-05-31):** Token-2022 (Token Extensions) is now +> **in MVP scope**. Most new tokens — including everything launched on Pump.fun — +> are Token-2022, so cleaning only classic SPL would miss the majority of real +> dust. PYRE supports Token-2022 conservatively, gating on account/mint +> **extensions** (see §7.1). The original brief's "skip Token-2022" stance is +> superseded by this revision. + --- ## 1. Project Summary @@ -131,9 +138,16 @@ believable. selected junk to zero; close emptied accounts after burn; show skipped/protected tokens; export/share receipt image. +**v0.1 token-program support:** classic **SPL Token** AND **Token-2022** token +accounts are scanned, classified, closed, and burned — Token-2022 only when its +account/mint extensions are safe to act on (see §7.1). Token-2022 accounts with +unhandled extensions (confidential transfer, withheld transfer fees, unknown +extensions) and all frozen accounts are skipped. + **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. +vault, custom PYRE Solana program, NFT handling, automatic valuable-token +sacrifice, custodial signing, background wallet automation, on-chain swap routing +(TRANSMUTABLE), or any Token-2022 confidential-transfer / fee-harvest flows. ### MVP v0.2 — Prometheus Meta Mixer AI generation from burned/cleaned token context. @@ -187,11 +201,21 @@ Token accounts are classified into conservative categories. 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. +- **UNSUPPORTED** — system cannot safely reason about it. Examples: unknown token + program, bad metadata, unsupported account layout, and **Token-2022 accounts or + mints carrying extensions PYRE does not yet safely handle** — confidential + transfer, accounts with withheld transfer fees, or any unrecognized extension + (see §7.1). -> **Default rule: Unknown means skip.** +Token-2022 accounts with only benign/no extensions are classified exactly like +classic SPL (EMPTY_CLOSE_ONLY / INCINERATE_ONLY / PROTECTED_SKIP), using the +Token-2022 program for the close/burn instructions. Transfer-hook and +permanent-delegate mints are still cleanable (burn/close don't trigger a transfer +hook, and you may always burn/close your own account) but are **flagged** and +excluded from any future swap. + +> **Default rule: Unknown means skip** — unknown token program *or* unknown/unsafe +> Token-2022 extension. --- @@ -199,8 +223,14 @@ Token accounts are classified into conservative categories. The classifier must be conservative. MVP rules: -- Classic SPL only. -- Skip Token-2022 by default. +- Support classic **SPL Token** and **Token-2022**; gate Token-2022 on its + account *and* mint extensions per §7.1 (skip confidential transfer, withheld + transfer fees, and any unknown extension). +- Use the correct token program per account for every instruction (classic vs + Token-2022); perform `CloseAccount` as a **top-level** instruction (CPI-Guard + safe). +- Reclaimable rent is the account's **live lamport balance** (Token-2022 rent + varies with extensions) — never a fixed constant. - Skip NFTs. - Skip compressed NFTs. - Skip LP tokens. @@ -216,14 +246,57 @@ The classifier must be conservative. MVP rules: > The system should never say *"This token is safe."* > It should say *"This token appears eligible based on current checks."* +### 7.1 Token-2022 (Token Extensions) Support + +Token-2022 accounts and mints can carry **extensions** that change what is safe +to close, burn, or swap. The scanner reads extensions from `jsonParsed` RPC data +on **both** the token account and its mint (transfer hook, permanent delegate, +and confidential-transfer config live on the *mint*). Closing requires a +zero-balance, non-frozen account; burning is owner-authorized and does **not** +invoke a transfer hook. + +Program IDs: +- Classic SPL Token — `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA` +- Token-2022 — `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb` + +Conservative per-extension policy (default for any **unknown extension → skip**): + +| Extension | close-empty | burn-then-close | swap (future) | +|---|---|---|---| +| None / Immutable-Owner / Memo / Metadata / Interest-Bearing | allow | allow | allow | +| Non-Transferable (soulbound) | allow | allow (owner may burn) | block | +| Transfer Hook (mint) | allow (no hook on close) | allow (no hook on burn) | **skip** + flag | +| Permanent Delegate (mint) | allow | allow + **scam flag** | **skip** + flag | +| Transfer Fee | allow only if **no** withheld balance | allow (harvest withheld before close) | allow, fee disclosed | +| Default-Frozen / account `state == frozen` | **skip** | **skip** | **skip** | +| Confidential Transfer | **skip** (needs drain + ZK-proof close) | **skip** | **skip** | +| CPI Guard | allow (close as top-level ix) | allow | review | +| Unknown / unrecognized | **skip** | **skip** | **skip** | + +Per-account preflight (server-side, never trust the client): +1. Read `info.state` — skip if `frozen`. +2. Read `tokenAmount.amount` — `0` ⇒ close path; non-zero ⇒ burn-then-close. +3. Read the token-account extensions — `confidentialTransferAccount` ⇒ skip; + `transferFeeAmount.withheldAmount > 0` ⇒ skip (harvest-first is out of MVP scope). +4. Read the **mint** extensions — transfer hook / permanent delegate ⇒ flag + (cleanable, but warn and exclude from swap). +5. Any unrecognized extension ⇒ UNSUPPORTED. +6. Reclaim = the account's live lamports; sign with the account owner / its + `CloseAuthority`. + +Out of MVP scope (later phases): confidential-transfer close (drain + ZK proof), +transfer-fee withheld-balance harvesting, and swapping hook/permanent-delegate +tokens. + --- ## 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. + token program, balance, decimals, rent estimate (live lamports), metadata if + available, token program type, frozen/delegated state, and — for Token-2022 — + the account **and mint** extension list (§7.1). 3. **Classification** — each account classified; UI groups into: closeable empty accounts, burnable junk, potentially transmutable scraps, protected/skipped, unsupported. @@ -445,9 +518,12 @@ spawn_records: id, generation_id, spawn_name, ticker, mint, metadata_ur 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. +**Token Safety:** Unknown assets default to skip — unknown token program *or* +unknown/unsafe Token-2022 extension (§7.1). Token-2022 is supported only when its +account/mint extensions are safe to act on; confidential-transfer, withheld-fee, +and frozen accounts are skipped. 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; diff --git a/docs/SECURITY.md b/docs/SECURITY.md index 33ae6e1..8957262 100644 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -46,8 +46,12 @@ For the MVP: ## Token safety -- Unknown assets default to **skip**. -- Token-2022 defaults to **skip** for the MVP. +- Unknown assets default to **skip** — unknown token program *or* unknown/unsafe + Token-2022 extension. +- Token-2022 is **supported** with conservative extension gating (design doc + §7.1): confidential-transfer, withheld-transfer-fee, frozen, and any + unrecognized-extension accounts are **skipped**; transfer-hook / + permanent-delegate mints are cleanable but **flagged**. - NFTs default to **skip**. - Valuable assets default to **skip**. - The user must **manually select** anything risky. diff --git a/docs/TOKEN_CLASSIFICATION.md b/docs/TOKEN_CLASSIFICATION.md index 619814f..069e1da 100644 --- a/docs/TOKEN_CLASSIFICATION.md +++ b/docs/TOKEN_CLASSIFICATION.md @@ -92,11 +92,13 @@ canonical enum lives in `packages/core` (see [Canonical enum](#canonical-enum)). - **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 + - **Token-2022 accounts/mints with extensions not yet safely handled** — + confidential transfer, withheld transfer fees, or any unrecognized extension + (see design doc §7.1). Token-2022 with benign/no extensions is classified + like classic SPL. --- @@ -105,8 +107,11 @@ canonical enum lives in `packages/core` (see [Canonical enum](#canonical-enum)). 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. +- [ ] Support classic SPL **and** Token-2022; gate Token-2022 on account+mint + extensions per design doc §7.1 (skip confidential transfer, withheld + transfer fees, frozen, and any unknown extension). Use the correct token + program per account; `CloseAccount` as a top-level instruction. +- [ ] Reclaimable rent = the account's live lamports (not a constant). - [ ] Skip NFTs. - [ ] Skip compressed NFTs. - [ ] Skip LP tokens. @@ -138,23 +143,31 @@ current automated checks, not a guarantee about the asset. 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 + raw/UI balance, decimals, metadata if available, token program type, + frozen/delegated state, and (Token-2022) the account **and mint** extension + list. +2. **Token program check** — classic SPL and Token-2022 are both supported. An + unknown/other token program ⇒ `UNSUPPORTED`. Stop. +3. **Extension check (Token-2022)** — if the account/mint carries an extension + PYRE does not safely handle (confidential transfer, withheld transfer fees, or + any unrecognized extension), classify as `UNSUPPORTED`. Stop. Transfer-hook / + permanent-delegate mints continue but are flagged (see design doc §7.1). +4. **Account integrity check** — bad/missing metadata or unsupported layout ⇒ `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 / +5. **Lock check** — frozen or delegated accounts are skipped regardless of + balance: classify as `PROTECTED_SKIP`. Stop. +6. **Empty check** — if the balance is zero (and classic-SPL/Token-2022 with safe + extensions, not frozen/delegated), classify as `EMPTY_CLOSE_ONLY`. Stop. + (Empty accounts hold no value, so they close regardless of mint identity.) +7. **Protected check** — for a NON-empty balance: if the asset is an NFT, + compressed NFT, LP token, receipt token, staked token, major/known-valuable + asset, SOL/WSOL special case, suspicious token, 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 +8. **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 + simulation passes), classify as `TRANSMUTABLE`. Stop. (No swap routing in MVP + v0.1, so this never fires yet.) +9. **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