<!-- file: docs/reports/RAYDIUM_STABLE_SWAP_EVENT_COVERAGE_REPORT.md -->

# Raydium Stable Swap event coverage report — 0.7.52 final

## Scope

`0.7.52` closes the `raydium_stable_swap` tranche after `0.7.51 raydium_amm_v4`.

Canonical local decoder code:

```text
raydium_stable_swap
```

Canonical program id validated by local corpus:

```text
5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h
```

Stable Swap is handled as a Raydium legacy AMM-style program with a one-byte instruction discriminator layout. Anchor-like 8-byte discriminants remain upstream discovery evidence only and are not business proof.

## Final implementation status

Implemented and locally validated:

- `kb_lib/src/dex/raydium_stable_swap.rs`.
- `RaydiumStableSwapDecoder` re-exported through `kb_lib/src/dex.rs` and `kb_lib/src/lib.rs`.
- Stable Swap route in `DexDecodeService` before generic Raydium instruction-audit preservation.
- One-byte Stable Swap instruction observation support.
- Coverage entries for all locally observed Stable Swap discriminants `00..0d`.
- Materialization into lifecycle/liquidity/fee/admin/orderbook/trade tables when the local corpus proves a safe target.
- Swap materialization from exact vault balance deltas only.
- Validation SQL in `validation_sql/SQL_VALIDATION_RAYDIUM_STABLE_SWAP_0_7_52.sql`.

## Instruction surface

| entry | discriminator | family | final target | local event kind | final status |
|---|---:|---|---|---|---|
| `initialize` | `00` | `pool_create` | `k_sol_pool_lifecycle_events` | `raydium_stable_swap.initialize` | observed/materialized when context complete |
| `init_model_data` | `01` | `model_setup` | decoded-only | `raydium_stable_swap.init_model_data` | observed decoded-only / explained |
| `update_model_data` | `02` | `admin_config` | `k_sol_pool_admin_events` | `raydium_stable_swap.update_model_data` | observed/materialized |
| `deposit` | `03` | `liquidity_add` | `k_sol_liquidity_events` | `raydium_stable_swap.deposit` | observed/materialized |
| `withdraw` | `04` | `liquidity_remove` | `k_sol_liquidity_events` | `raydium_stable_swap.withdraw` | observed/materialized |
| `monitor_step` | `05` | `order_place` | `k_sol_orderbook_events` | `raydium_stable_swap.monitor_step` | observed/materialized |
| `set_params` | `06` | `admin_config` | `k_sol_pool_admin_events` | `raydium_stable_swap.set_params` | observed/materialized |
| `withdraw_pnl` | `07` | `fee` | `k_sol_fee_events` | `raydium_stable_swap.withdraw_pnl` | observed/materialized |
| `withdraw_srm` | `08` | `fee` | `k_sol_fee_events` | `raydium_stable_swap.withdraw_srm` | observed/materialized when context complete |
| `swap_base_in` | `09` | `swap` | `k_sol_trade_events` only from vault deltas | `raydium_stable_swap.swap_base_in` | observed, materialized for successful swaps with exact deltas |
| `pre_initialize` | `0a` | `pool_create` | decoded-only or lifecycle when complete | `raydium_stable_swap.pre_initialize` | observed decoded-only / explained in current corpus |
| `swap_base_out` | `0b` | `swap` | `k_sol_trade_events` only from vault deltas | `raydium_stable_swap.swap_base_out` | observed, materialized for successful swaps with exact deltas |
| `simulate_info` | `0c` | `cpi_transport` | decoded-only | `raydium_stable_swap.simulate_info` | observed decoded-only / explained |
| `admin_cancel_orders` | `0d` | `orderbook_admin` | `k_sol_orderbook_events` | `raydium_stable_swap.admin_cancel_orders` | observed/materialized when context complete |
| `swap_event` | `40c6cde8260871e2` | `cpi_transport` | decoded-only | `raydium_stable_swap.swap_event` | upstream mapped, not observed in local corpus |

## Swap amount policy

Stable Swap instruction arguments are retained as instruction bounds, but they are not sufficient for trade/candle materialization:

```text
swap_base_in:
  amountInRaw = exact input argument
  minimumAmountOutRaw = slippage lower bound, not exact output

swap_base_out:
  amountOutRaw = requested output argument
  maxAmountInRaw = slippage upper bound, not exact input
```

Therefore, `swap_base_in` and `swap_base_out` materialize as trades/candles only when exact base/quote amounts are inferred from vault balance deltas:

```text
amountSource = stable_swap_vault_balance_delta
```

Instruction-bound-only swaps remain decoded-only:

```text
amountSource = stable_swap_instruction_bounds_only
tradeCandidate = false
candleCandidate = false
```

For failed transactions the skip reasons are:

```text
skipTradeReason = failed_transaction
skipCandleReason = failed_transaction
```

For successful transactions where exact vault deltas cannot be proven, the expected skip reason is:

```text
stable_swap_exact_amounts_unresolved
```

The final local corpus has no successful unresolved Stable Swap swap.

## Final local validation snapshot

Latest confirmed local commands:

```text
cargo test -p kb_lib
407 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

cargo clippy -p kb_lib --all-targets -- -D warnings
ok
```

Latest replay snapshot:

```text
replayed=298
decode_skipped=0
ledger_upserts=298
unsafe_ledger_rows=258
trades=290
liquidity=16
lifecycle=4
token_account=0
candle_upserts=1160
instructionObservations=5317
resetDeleted=1059
catalog=40 tokens / 59 pools / 59 pairs
```

Stable Swap swap closure:

| event kind | amount source | tx status | decoded | trades |
|---|---|---|---:|---:|
| `raydium_stable_swap.swap_base_in` | `stable_swap_instruction_bounds_only` | failed | 27 | 0 |
| `raydium_stable_swap.swap_base_in` | `stable_swap_vault_balance_delta` | success | 171 | 171 |
| `raydium_stable_swap.swap_base_out` | `stable_swap_instruction_bounds_only` | failed | 2 | 0 |
| `raydium_stable_swap.swap_base_out` | `stable_swap_vault_balance_delta` | success | 4 | 4 |

UI smoke evidence after the vault-delta correction:

```text
pair 27, timeframe 60s -> 70 candles
pair 30, timeframe 60s -> 44 candles
```

## Final invariant status

Validated as clean on the local corpus:

- residual `raydium_stable_swap.instruction_audit`: empty;
- residual `upstream_git.instruction_match` for covered local entries: empty;
- decoded-without-coverage: empty;
- non-swap materialized as trade: empty;
- failed transaction materialized as business trade: empty;
- multi-target materialization: empty;
- successful non-materialized swaps without skip reason: empty;
- Stable Swap successful swaps with `stable_swap_vault_balance_delta`: `trade_count = decoded_count`;
- Stable Swap instruction-bound-only swaps: failed only, `trade_count = 0`.

## Closure decision

`0.7.52 raydium_stable_swap` is closed for the currently observed local corpus.

The decoder has detected all locally observed Stable Swap instruction discriminants, materialized every event that can safely be materialized, and preserved non-materializable/failed events as decoded-only with explicit reasons.

Future work is not a blocker for `0.7.52` and should be handled as a later tranche if a new local corpus reveals additional discriminants or a direct, reliable `swap_event` path.
