# Astra re-audit: Slawth Vawlt program v1.4

**Auditor:** Astra (OpenAI Codex CLI, the maintainer's default model) · **Date:** 2026-09-08 · **Scope:** commit `5d91406` (v1.4) via the re-audit packet (both v1.2 reports, full source, tests, keeper) · **Method:** read-only, report unedited below (personal names redacted).

**Response (v1.6, same day):** AST-11 fixed (guard fails closed: full-window coverage required, market registration gated on it); AST-12 fixed (route slots 3/4/5 bound, nonzero quote required); AST-13 accepted pending the first real on-chain compound (a mainnet simulation of a real ZEC to ZCAT route with an explicit destination shows one Token-2022 transfer straight into the destination and the destination receiving exactly the quoted amount: `scripts/dev/jupiter-trace-probe.mjs`); AST-14 fixed (keeper counts only error-free, fetched-back transactions whose enrollment counter moved); AST-15 fixed (creator-fee pools refused at registration and compound); AST-16 fixed (`last_update_timestamp` endpoint, verified against a live pool); AST-17 accepted with the keeper allowlisting intermediate mints; AST-18 fixed (ladder reaches the minimum); AST-19 fixed (`FeeCanOnlyGoDown`). Of the partial/missing prior findings: AST-03/F4 remain the planned freeze; AST-05 accepted (post-swap balance checks bound a tail/executor disagreement to a failed compound, never an underpayment); AST-09 discriminators now re-checked on every compound; F9 cosmetic. Per-finding status is on the site's audits page.

---

## Summary

v1.4 materially improves signer isolation, donation handling, account binding, Token-2022 cap handling, and enrollment lifecycle behavior. However, the TWAP remediation fails open, while a zero output floor combined with unbound Jupiter destination accounts creates a conditional permissionless loss path. The proposed ZEC→ZCAT deployment also depends on an unverified two-transfer Token-2022 delivery path, and the keeper can report failed transactions as successful. **Recommendation: DO NOT DEPLOY v1.4 for production or burn its upgrade authority; a disposable maintainer-only staging deployment is acceptable only with no third-party approvals and manual on-chain verification.**

## Prior-finding remediation

Line numbers below are source-relative, as printed in the v1.4 packet.

| ID | Verdict | v1.4 evidence | Residual risk |
|---|---|---|---|
| AST-01 | **PARTIAL** | `programs/slawth-vawlt/src/instructions/compound.rs:159-208`; `programs/slawth-vawlt/src/raydium.rs:87-116,169-199`; `programs/slawth-vawlt/src/constants.rs:15-19` | A direction-aware spot/TWAP comparison now exists, but unusable, short, or stale history silently disables it. The actual floor is still derived from spot, and no minimum-liquidity or independent-oracle condition exists. See AST-11. |
| AST-02 | **COMPLETE** | `programs/slawth-vawlt/src/instructions/add_market.rs:14-24,35-45`; `programs/slawth-vawlt/src/instructions/compound.rs:20-46,114-149,219-225`; `programs/slawth-vawlt/src/jupiter.rs:45-60` | The global delegate/fee-vault authority no longer signs Jupiter CPI; only a per-market swap PDA does. That PDA can nevertheless own setup-created auxiliary ATAs, addressed in AST-17. |
| AST-03 | **MISSING** | `programs/slawth-vawlt/src/instructions/initialize.rs:8-14`; `programs/slawth-vawlt/src/instructions/enroll.rs:46-66` | Initialization authenticates but does not revoke the loader upgrade authority, while enrollment still grants `u64::MAX`. The planned external burn is not a v1.4 code fix and must precede every third-party approval. |
| AST-04 | **COMPLETE** | `programs/slawth-vawlt/src/instructions/compound.rs:66-77,151-155,169-172,213-217` | The original missing maximum-fee and second-leg calculations are fixed: the current epoch/cap is used and user-to-transit net receipt is measured. The distinct route-transfer-count problem remains; see AST-13. |
| AST-05 | **MISSING** | `programs/slawth-vawlt/src/jupiter.rs:19-30`; `scripts/vawlt/lib.mjs:8-12` | Both parsers still read the final 19 bytes without deserializing `routePlan`, establishing canonical encoding, or requiring EOF. Plain-route restriction and postconditions reduce impact but do not fix parser/executor disagreement. |
| AST-06 | **PARTIAL** | `programs/slawth-vawlt/src/math.rs:32-49`; `programs/slawth-vawlt/src/instructions/compound.rs:92-97,183-187`; `scripts/vawlt/lib.mjs:74-100` | Explicit partial amounts mitigate oversized swaps, but the CLMM reference remains linear spot multiplication without liquidity, tick traversal, price impact, or dynamic-fee behavior. |
| AST-07 | **COMPLETE** | `programs/slawth-vawlt/src/instructions/compound.rs:92-97,119,151-157,227-232` | `amount` is explicit; `in_amount` may range from the new contribution through total transit; exact unswapped surplus must remain. A balance increase no longer invalidates the transaction. The production keeper does not fully exploit this flexibility; see AST-18. |
| AST-08 | **PARTIAL** | `scripts/vawlt/lib.mjs:54-68` | Arbitrary System/token instructions are refused, payer is rewritten, foreign signers are rejected, and only derived swap-PDA ATAs may be created. Mint and token-program identifiers remain unrestricted, permitting malicious-API rent grief. |
| AST-09 | **PARTIAL** | `programs/slawth-vawlt/src/instructions/add_market.rs:60-90`; `programs/slawth-vawlt/src/instructions/compound.rs:79-85,164-168,189-208`; `programs/slawth-vawlt/src/raydium.rs:18-24` | Registration now verifies owners, discriminators, pool/config/observation relationships, and mints. Compound does not recheck discriminators; CPMM vaults are not fully decoded for initialized state or internal authority. |
| AST-10 | **COMPLETE** | `programs/slawth-vawlt/src/instructions/unenroll.rs:21-47` | The canonical ATA is mandatory/recreated, and an unrelated delegate is preserved. `revoke=false` intentionally leaves the Vawlt delegation, so the client must present that choice unambiguously. |
| F1 | **COMPLETE** | `programs/slawth-vawlt/src/instructions/add_market.rs:14-24,35-45`; `programs/slawth-vawlt/src/instructions/compound.rs:114-149,219-225`; `programs/slawth-vawlt/src/jupiter.rs:45-60` | Same resolution as AST-02: Jupiter cannot receive the global user-delegate or fee-vault signature. Unbound output accounts become material when the output floor is zero; see AST-12. |
| F2 | **PARTIAL** | `programs/slawth-vawlt/src/instructions/compound.rs:159-208`; `programs/slawth-vawlt/src/raydium.rs:87-116,169-199` | Fresh adverse spot movement is bounded, but the guard fails open and the accepted history may cover only 60 seconds. |
| F3 | **COMPLETE** | `programs/slawth-vawlt/src/instructions/compound.rs:119,151-157,227-232`; `programs/slawth-vawlt/src/jupiter.rs:32-40` | Range validation and exact surplus preservation remove the deterministic front-run-donation revert. |
| F4 | **MISSING** | `programs/slawth-vawlt/src/instructions/initialize.rs:8-14`; `programs/slawth-vawlt/src/instructions/enroll.rs:46-53` | Same as AST-03: all approved reward balances remain exposed to a malicious upgrade until the on-chain `ProgramData` authority is actually `None`. |
| F5 | **COMPLETE** | `programs/slawth-vawlt/src/lib.rs:62-64`; `programs/slawth-vawlt/src/instructions/unenroll.rs:34-47`; `programs/slawth-vawlt/src/instructions/enroll.rs:69-100` | `unenroll(false)` preserves the shared delegate and `reapprove` repairs a revoke. `unenroll(true)` still disables sibling markets, but it is now explicit and recoverable. |
| F6 | **COMPLETE** | `programs/slawth-vawlt/src/instructions/add_market.rs:60-90`; `programs/slawth-vawlt/src/instructions/compound.rs:164-168` | The pool's embedded config is bound at registration and its owner is rechecked during compound. Residual trust remains in later Raydium program upgrades. |
| F7 | **PARTIAL** | `programs/slawth-vawlt/src/instructions/enroll.rs:56-66,69-100` | `reapprove` fixes revoked or recreated-ATA recovery without changing the floor. A true unenroll followed by re-enroll still snapshots the entire current balance as the new floor. |
| F8 | **PARTIAL** | `programs/slawth-vawlt/src/math.rs:32-49`; `programs/slawth-vawlt/src/instructions/compound.rs:92-97`; `scripts/vawlt/lib.mjs:74-100` | Same as AST-06: partial sizing mitigates but does not make the CLMM reference executable-size-aware. |
| F9 | **MISSING** | `programs/slawth-vawlt/src/instructions/compound.rs:104-149,234-245` | `fee`, `total_fees`, and the event still record the gross user debit, not the spendable amount received by a Token-2022 fee vault. This remains cosmetic accounting drift. |

## New findings

### AST-11 — High — The TWAP remediation fails open

**File and line:** `programs/slawth-vawlt/src/raydium.rs:89-115,171-199`; `programs/slawth-vawlt/src/instructions/compound.rs:176-183,202-208`; `programs/slawth-vawlt/src/instructions/add_market.rs:52-90`; `programs/slawth-vawlt/tests/test_compound.rs:388-415`; `programs/slawth-vawlt/tests/test_cpmm.rs:172-179`

**Description:** Both TWAP readers return `None` for uninitialized history, less than 60 seconds of history, or a newest observation more than one hour old. Both compound branches use `if let Some(...)`, so `None` silently restores a spot-only floor. Registration does not require an observation to be ready, and the nominal five-minute guard accepts only one minute of coverage.

**Concrete scenario:** An admin registers a fresh CPMM reference, or an inactive CPMM observation becomes stale. An attacker donates reward tokens directly to its reward-side vault, depressing the raw reserve spot without updating the oracle, then compounds a victim while the guard is skipped. The adverse spot becomes the sole reference floor, restoring AST-01's underpayment path.

**Code-level fix:** Make missing TWAP data an error, for example `twap.ok_or(VawltError::OracleUnavailable)?`; verify the initialized flag, require fresh full-window coverage, and gate market activation until the oracle is ready. Add a minimum-liquidity condition or independent oracle because a low-liquidity TWAP can itself be manipulated.

**Status:** **CONFIRMED.** The included tests explicitly assert that stale history permits compounding.

### AST-12 — High (conditional) — A zero floor plus unbound Jupiter output accounts permits reward theft

**File and line:** `programs/slawth-vawlt/src/constants.rs:32-38`; `programs/slawth-vawlt/src/jupiter.rs:45-51`; `programs/slawth-vawlt/src/math.rs:76-82`; `programs/slawth-vawlt/src/instructions/admin.rs:71-78`; `programs/slawth-vawlt/src/instructions/compound.rs:213-232`

**Description:** Slawth binds Jupiter slots 1, 2, and 6, but not `user_destination_token_account` at slot 3, optional destination at slot 4, or destination mint at slot 5. It also does not require `expected`, `threshold`, `quoted_out_amount`, or `received` to be positive. The [official Jupiter IDL](https://github.com/jup-ag/instruction-parser/blob/main/src/idl/jupiter.ts) confirms these are independent route accounts.

**Concrete scenario:** For a dust-sized generic market, `expected == 1` and nonzero slippage rounds `threshold` to zero; a 100% target transfer-fee epoch can similarly make `expected == 0` for a large amount. A permissionless caller supplies a route that consumes the bound transit but sends its output to an attacker-controlled destination or different mint. The user receives zero, yet `received >= 0` and `transit == swap_in - in_amount` both pass.

**Code-level fix:** Bind slot 5 to `target_mint` and bind the effective destination—slot 4 when present, otherwise slot 3—to `user_target_ata`; if an intermediate slot-3 ATA is required, bind it to the canonical swap-PDA target ATA. Reject unless `venue_in`, `after_pool`, `expected`, `threshold`, `quoted_out_amount`, and actual `received` are nonzero and economically meaningful.

**Status:** **CONFIRMED** for the missing invariant and included mock-router path. The packet's configured ZEC→ZCAT minimum is not dust-sized, but the immutable pair-generic program permits affected future configurations.

### AST-13 — Medium, deployment-blocking — Correct Token-2022 fee math is applied to an unproven transfer count

**File and line:** `programs/slawth-vawlt/src/instructions/compound.rs:66-77,169-172,213-218`; `test-programs/mock-router/src/lib.rs:42-67`; `programs/slawth-vawlt/tests/test_compound.rs:24-36,67-80`

**Description:** `calculate_epoch_fee` is correct for one transfer, but the reference assumes one reward transfer from transit into the route and one target transfer to the user. Jupiter `routePlan` is a trade DAG, and its plain route exposes both an intermediate user destination and an optional final destination in the [official IDL](https://github.com/jup-ag/instruction-parser/blob/main/src/idl/jupiter.ts). A live no-submit ZEC→ZCAT build observed during this review used slot 3 for the swap-PDA's ZCAT ATA and slot 4 for the user ATA, implying venue→slot-3 and slot-3→slot-4 transfers; split routes can also transfer the same fee-bearing mint multiple times.

**Concrete scenario:** With a non-cap-binding 3% target fee, two target transfers deliver approximately `after_pool × 0.97²`, while Slawth requires roughly `after_pool × 0.97 × 0.98` at 2% slippage. An honest real route then reverts even though the mock succeeds because the mock sends directly from its vault to slot 4 once. Per-transfer ceilings and caps also mean `fee(total) != Σ fee(parts)` for split routes.

**Code-level fix:** The safest v1 fix is to reject fee-bearing route-facing mints until this is resolved. Otherwise fully deserialize and constrain `routePlan`, bind both destination roles, permit only route shapes with a fixed transfer count, and apply the active fee sequentially to each transfer.

**Status:** **PLAUSIBLE.** It requires a submitted production Jupiter CPI trace with the actual ZCAT fee configuration; the current mock cannot settle it. Do not burn the upgrade authority before that test.

### AST-14 — Medium — The keeper treats landed transaction failures as successes

**File and line:** `scripts/keeper/keeper.mjs:58-62,104-127`

**Description:** `confirmTransaction` is awaited but its returned `value.err` is discarded. `getTransaction` is then used for compute and fee data without inspecting `info.meta.err`; the caller increments `compounded`, quoted output, and fees and clears backoff.

**Concrete scenario:** A transaction lands with `SlippageExceeded` after a quote race. The RPC call resolves normally with an on-chain error, but the keeper logs a successful compound and may count it toward the proposed "two live compounds" validation gate before the upgrade authority is burned.

**Code-level fix:** Inspect and throw on both `confirmation.value.err` and `info.meta.err`; require a non-null transaction record after bounded retries. Before recording success, verify the `Compounded` event or the expected enrollment count/timestamp and target balance delta.

**Status:** **CONFIRMED.**

### AST-15 — Medium — CPMM expected output omits optional creator fees

**File and line:** `programs/slawth-vawlt/src/raydium.rs:121-155,201-207`; `programs/slawth-vawlt/src/math.rs:51-61`; `programs/slawth-vawlt/src/instructions/compound.rs:189-209`

**Description:** Slawth subtracts already-accrued creator-fee counters from reserves but reads only `trade_fee_rate` for the next swap. Current Raydium CPMM state also contains per-pool `creator_fee_on` and `enable_creator_fee`, while `AmmConfig` contains a mutable `creator_fee_rate`; Raydium's swap calculation applies that fee independently. This behavior is present in the official [PoolState](https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/states/pool.rs), [AmmConfig](https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/states/config.rs), and [swap implementation](https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/instructions/swap_base_input.rs).

**Concrete scenario:** A creator-fee-enabled pool is registered, or its shared config's creator rate increases. Slawth quotes a trade-fee-only output above what the pool can deliver; once the omitted fee plus price impact exceeds permitted slippage, every honest compound reverts.

**Code-level fix:** Either reject `enable_creator_fee` during registration and recheck it during compound, or parse the rate, enable flag, and direction and reproduce Raydium's exact input-versus-output, ceiling, and reserve semantics.

**Status:** **CONFIRMED.** This is conservative rather than a below-floor fund-loss bug, but it can disable a configured CPMM market.

### AST-16 — Medium — CPMM TWAP uses the wrong cumulative endpoint timestamp

**File and line:** `programs/slawth-vawlt/src/raydium.rs:157-199`; `programs/slawth-vawlt/src/raydium.rs:253-268`; `programs/slawth-vawlt/tests/test_cpmm.rs:90-98`

**Description:** The reader treats the latest ring entry's `block_timestamp` as the endpoint for both cumulative value and elapsed time. Raydium updates the current entry's cumulative during sub-15-second swaps without changing that entry timestamp, and records the actual endpoint separately in `last_update_timestamp`; see the official [CPMM oracle implementation](https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/states/oracle.rs).

**Concrete scenario:** An entry at `t=1000` represents `300p` since an old sample at `t=700`. An in-place update at `t=1010` changes it to `310p` but leaves the entry timestamp at `1000`; Slawth returns `310p / 300 = 1.033p` rather than `p`, enough to reject an honest spot at the maximum 3% tolerance.

**Code-level fix:** Read `last_update_timestamp` at byte 4043 and use it for cumulative endpoint, span, and freshness. Require `entry_timestamp <= last_update_timestamp <= now`; permit an explicitly tested fallback to the entry timestamp only for legacy zero-valued accounts.

**Status:** **CONFIRMED.**

### AST-17 — Low — The per-market swap PDA does not own only the transit account

**File and line:** `programs/slawth-vawlt/src/state.rs:46-48`; `programs/slawth-vawlt/src/instructions/compound.rs:31-44,219-225`; `programs/slawth-vawlt/src/jupiter.rs:54-60`; `scripts/vawlt/lib.mjs:54-68`

**Description:** Anyone may create or fund an ATA owned by the swap PDA, and the keeper explicitly creates intermediate swap-PDA ATAs. The setup allowlist verifies derivation but does not restrict mint or token-program IDs. Those accounts share the signer capability exposed to Jupiter, and their balances have no Slawth pre/post invariant.

**Concrete scenario:** A compromised Jupiter API includes valid ATA-create instructions for arbitrary attacker-created mints. The transaction can still compound successfully while charging the keeper rent for each account. Route-created dust or deliberately stranded value in a legitimate intermediate ATA is also not protected against a later PDA-signed route.

**Code-level fix:** Pre-create and whitelist an audited set of `(mint, token program, ATA)` tuples per market, reject every other setup instruction, and assert zero or expected deltas for every swap-PDA-owned account used by a route. Add a narrowly bound sweep/close mechanism before immutability.

**Status:** **CONFIRMED** for additional ownership and rent grief; extraction through a particular production Jupiter adapter remains route-dependent.

### AST-18 — Low — Keeper halving does not reach the advertised minimum and always consumes surplus

**File and line:** `scripts/vawlt/lib.mjs:74-100`; `scripts/keeper/keeper.mjs:41-52`

**Description:** The six-attempt loop tests only `pending`, `/2`, `/4`, `/8`, `/16`, and `/32`. It can update `amount` to `/64` after the final test but returns the stale `/32` plan. It also always quotes `transit_before + contributed`, although the on-chain range permits leaving old surplus untouched.

**Concrete scenario:** A route becomes viable only at `/64` or at `min_compound`; the keeper reports failure "even at the market minimum" without testing either. Separately, a sufficiently large transit donation makes every keeper quote include the donation and can block the market even though a contribution-only on-chain route would remain valid.

**Code-level fix:** Iterate until the minimum has been explicitly evaluated, with a separate API-attempt cap. For every amount, try `in_amount = contributed` before optionally including surplus, and leave the exact surplus enforced by the existing postcondition.

**Status:** **CONFIRMED.**

### AST-19 — Informational — "Fee can only ever be lowered" is not enforced

**File and line:** `programs/slawth-vawlt/src/constants.rs:10-13`; `programs/slawth-vawlt/src/instructions/admin.rs:48-58`

**Description:** The 200-bps hard cap is enforced, but `set_params` permits any new value at or below 200, including raising a previously lowered fee.

**Concrete scenario:** The admin lowers the fee from 200 to 50 bps and later raises it back to 200, contradicting the source and revision-note guarantee on which users may rely.

**Code-level fix:** Enforce `new_fee_bps <= config.fee_bps`, or remove the monotonicity claim from the specification and user interface.

**Status:** **CONFIRMED.**

## Checked and sound

Static review found the following controls internally sound, subject to the findings above:

- `initialize` derives the canonical upgradeable-loader `ProgramData` account and authenticates its current upgrade authority.
- Config, market, enrollment, global authority, and per-market swap PDAs use canonical seeds and stored bumps.
- Compound binds the directed mint pair, both token programs, enrollment/user, canonical user ATAs, transit ATA, fee vault, stored reference accounts, and pinned executable Jupiter address.
- Splitting the global delegate from the per-market Jupiter signer closes the prior cross-user, cross-market, and fee-vault CPI authority class.
- Only plain Jupiter `route` is accepted; shared/exact-out discriminators are rejected. Slots 1, 2, and 6 are checked, and caller-supplied signer flags are stripped.
- Explicit `amount`, measured transit contribution, bounded `in_amount`, and exact surplus preservation correctly handle balance increases and post-quote transit donations.
- For usable observations, CLMM ring traversal and mathematical floor division for negative ticks are correct. The adverse-price direction is correct for reward-as-token-0 and reward-as-token-1.
- CPMM reciprocal accumulator selection and the one-sided spot/TWAP comparison are directionally correct.
- Registration checks Raydium owners and all three discriminators, binds pool→config, pool→observation and observation→pool, and verifies the two market mints in either direction.
- CPMM reserve calculation subtracts protocol, fund, and accrued creator fees; vault address, owning token program, and mint bytes are checked.
- `TransferFeeConfig::calculate_epoch_fee` supplies the correct current-epoch basis points, ceiling, and maximum cap for each individual modeled transfer.
- Creator-fee-disabled CPMM constant-product arithmetic and static trade-fee arithmetic are checked and use wide integers.
- The fee and slippage caps are 200 bps and the TWAP-tolerance cap is 300 units. The CLMM tolerance is intentionally ticks—approximately, not exactly, basis points.
- `withdraw_fees` is restricted to the Config admin, the canonical fee vault, and the admin's ATA.
- `reapprove` requires the enrolled user and leaves the floor untouched. `unenroll` uses the canonical reward ATA and revokes only the Vawlt delegate when requested.
- Enrollment, reapproval, unenrollment, and fee withdrawal remain available while compounding is paused, preserving an exit path.

## Remaining test gaps

- Submit a real Jupiter CPI—not merely an API build or mock—for ZEC→ZCAT and the reverse direction. Trace slots 3/4, actual transfer count, base and withheld balance deltas, and the active ZCAT fee cap before any authority burn.
- Fork-test the exact deployed Jupiter binary for appended suffixes, canonical EOF, malformed/duplicate aliases, destination and mint substitution, plain-route DAG splits, and every reachable adapter.
- Test zero `expected`, zero `threshold`, `expected == 1`, `min_compound == 0`, 10,000-bps transfer fees, and an attacker-controlled output destination.
- Add fail-closed tests for uninitialized, less-than-60-second, stale, and less-than-full-window observations for both CLMM and CPMM. Include low-liquidity manipulate→compound→unwind scenarios and CPMM raw-vault donations.
- Test real CPMM in-place oracle updates using `last_update_timestamp`, 99→0 ring wrap, reverse/token-1 direction, exact window boundaries, and future/invalid timestamps.
- Test CPMM creator fees on input and output, every `creator_fee_on` direction, disabled/enabled pools, and later config-rate changes.
- Test CLMM tick traversal, exhausted or discontinuous liquidity, dynamic-fee pools, fee-on-output modes, and amounts at the keeper's halving/minimum boundaries.
- Test Token-2022 fees with cap binding and nonbinding, per-transfer rounding, split routes, epoch rollover, fee-config mutation, and fee-bearing reward as well as target mints.
- Explicitly reject or test unsupported Token-2022 extensions such as transfer hooks, default-frozen accounts, non-transferable mints, and CPI-guarded accounts.
- Fund every swap-PDA intermediate ATA, deliberately strand route dust, and verify whether a later route can spend it. Test malicious setup responses with arbitrary valid mints, token programs, instruction counts, and rent charges.
- Test keeper plans at `/64` and the exact market minimum, plus contribution-only routing when a large pre-existing transit surplus exists.
- Make a landed failed transaction return through `confirmTransaction` and verify the keeper records failure, retains backoff, and does not add quoted output or fees to status.
- Add `withdraw_fees` tests for full, partial, overdrawn, SPL, and Token-2022 withdrawals and wrong vault/mint/program/recipient substitutions.
- Test `reapprove` after closing and recreating the ATA; sibling-market `unenroll(true/false)` behavior; last-enrollment `revoke=false`; and unenroll→re-enroll floor reset.
- Add a monotonic-fee test if "can only lower" remains a requirement.
- Reproduce the deployed Slawth binary, verify the two real compounds through balances, events, and successful transaction metadata, and independently verify `ProgramData.upgrade_authority_address == None` before accepting public enrollments.
- Pin and archive the exact deployed Jupiter and Raydium binaries/layouts used for validation; Slawth's own authority burn does not freeze those external dependencies.
- The packet provides only an excerpt of `scripts/vawlt/lib.mjs`; `referenceQuote`, `transferFeeOn`, ALT construction, and several other keeper helpers were therefore not auditable for off-chain/on-chain parity.
- This re-audit inspected the packet's test source but could not execute it because the workspace contains the Markdown packet rather than a buildable repository and fixture set.
