feat(transmute): sell-route detection (Jupiter) + design Rev 3

Re-prioritizes the core loop (sell→feed→close; burn for unsellable only) per
user direction. READ-ONLY this increment — quotes + risk flags only, no swap
build/sign, no funds moved.

- docs: Rev 3 — §5 scope, §6 TRANSMUTABLE active, new §6.1 (Jupiter Ultra
  routing incl. pump.fun pre/post-graduation + Token-2022; 3rd-party-swap trust
  model = simulate + lamports-delta ≥ min-out + sole-signer + no
  SetAuthority/Approve/bad-CloseAccount; Shield; price-impact/slippage/dust
  guards; Essence model 1 = opt-in off-chain tally, no custody).
- @pyre/core: SellInfo type + TokenAccountDto.sell.
- @pyre/api: keyless Jupiter client (lite-api: /swap/v1/quote + /ultra/v1/shield);
  bounded /api/scan enrichment — upgrades INCINERATE_ONLY→TRANSMUTABLE when a
  worthwhile route exists; dust gate (proceeds ≤ fee+rent → keep burn); price
  impact >10% blocks; graceful degrade if Jupiter down.
- @pyre/web: shows "Sellable for ~X SOL", price impact, Shield chips; disabled
  "Sell & feed the PYRE (soon)" CTA (execution is the next, audited step).

Tracker: Phase 6 "swap candidate detection" + "route quote preview" done.
typecheck 8/8, core 85, solana 19, web build green.

LIVE FINDING: both pump.fun tokens ARE routable via Jupiter (so no pump.fun
engine needed) but quote ~0.0000097 SOL each — far below their ~0.002 SOL rent,
so the dust gate correctly keeps them INCINERATE_ONLY ("not worth selling").

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-31 05:11:20 +00:00
parent 00f9a96286
commit f9c471ef71
10 changed files with 599 additions and 18 deletions

View File

@@ -11,6 +11,13 @@
> 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.
>
> **Revision note — Rev 3 (2026-05-31):** The core loop is *sell sellable tokens
> → feed the PYRE (opt-in Essence) → close the emptied account*; **burning is for
> unsellable tokens only**. Selling (TRANSMUTABLE) is pulled into near-term scope
> via the **Jupiter** aggregator (§6.1) — PYRE builds no swap math and runs no
> pump.fun engine. Essence is **model 1**: net SOL stays in the user's wallet and
> is recorded as an opt-in off-chain tally; **no custody** until the v1.0 program.
---
@@ -144,10 +151,16 @@ 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, 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.
**Selling scraps (Transmute) is now near-term scope** (Rev 3 — see §6.1): the core
loop is *sell sellable tokens for SOL → feed the PYRE (opt-in Essence) → close the
emptied account*; burning is reserved for genuinely unsellable tokens. Selling is
routed through Jupiter (third-party aggregator); PYRE never builds the swap math
itself and never takes custody (Essence is an opt-in off-chain tally — model 1).
**v0.1 must NOT include:** automatic Pump.fun launch, custom PYRE Solana program,
NFT handling, automatic valuable-token sacrifice, custodial signing, background
wallet automation, any Essence VAULT/custody (no "deposit" until the v1.0 on-chain
program), or any Token-2022 confidential-transfer / fee-harvest flows.
### MVP v0.2 — Prometheus Meta Mixer
AI generation from burned/cleaned token context.
@@ -194,9 +207,12 @@ Token accounts are classified into conservative categories.
- **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**.
- **TRANSMUTABLE** — has a safe swap route (via Jupiter, §6.1) that passes the
price-impact / slippage / dust guards. *Action:* user may swap the token into
SOL; the net SOL stays in the user's wallet, and may be recorded as Essence
("feed the PYRE") **only if the user opts in** (off-chain tally, no custody).
This is the preferred outcome for any token with real liquidity — burning is
for unsellable tokens only.
- **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,
@@ -217,6 +233,43 @@ excluded from any future swap.
> **Default rule: Unknown means skip** — unknown token program *or* unknown/unsafe
> Token-2022 extension.
### 6.1 Selling scraps (Transmute) — Jupiter + the third-party-swap trust model
A non-empty token is **TRANSMUTABLE** (preferred over burning) when it has a safe
route to SOL. PYRE does **not** implement swap math or run a pump.fun engine — it
uses **Jupiter** as the aggregator:
- **Routing:** Jupiter **Ultra** (`/ultra/v1/order` → user signs → `/ultra/v1/execute`,
keyless via `lite-api.jup.ag`) routes both **pre- and post-"graduation" pump.fun**
tokens and **Token-2022**. If Ultra returns no route for a mint, optionally fall
back to **PumpPortal**'s keyless local-trade API (bonding-curve sell); if neither
routes, the token is unsellable → INCINERATE_ONLY or close-for-rent.
- **Output:** sell to wSOL with `wrapAndUnwrapSol` so the user receives **native SOL**.
- **Risk pre-screen:** call Jupiter's **Shield** API per mint; surface
freeze/mint-authority and low-liquidity warnings.
- **Guards (a route alone is not enough):** block if `priceImpactPct` exceeds the
threshold (warn ~23%, hard cap ~10%); cap slippage; and a **dust gate** — if the
estimated NET SOL ≤ (tx fee + reclaimable rent), selling is not worth it → keep it
INCINERATE_ONLY / suggest close-for-rent instead.
**Trust model for a third-party-built swap tx (critical).** The swap transaction is
built by Jupiter, not PYRE, and is multi-instruction with address-lookup-tables —
so it **cannot be byte-matched** the way our own close/burn tx is (§16). Before the
user signs, PYRE must instead:
1. **Simulate** the transaction and confirm the user's **SOL balance delta ≥
`otherAmountThreshold`** (the quote's min-out) with no simulation error — this
validates the economic effect regardless of route structure.
2. Confirm the **only required signer is the user** (no co-signer / foreign fee payer).
3. Scan instructions and **reject any `SetAuthority`, delegate `Approve` to a foreign
address, or `CloseAccount` whose destination is not the user**.
4. Confirm proceeds credit the **user's** account.
The user always signs in their own wallet (PYRE never holds keys). **Essence
("feed the PYRE") = the net SOL is recorded as an opt-in, off-chain tally only;
proceeds stay in the user's wallet and PYRE takes no custody** until the v1.0
on-chain program. Rent and Essence are always kept separate (§3).
---
## 7. Token Safety Rules