-- file: validation_sql/SQL_VALIDATION_RAYDIUM_AMM_V4_0_7_51.sql
-- Validation finale de la tranche 0.7.51 raydium_amm_v4.
-- À exécuter après replay forceDexDecode=yes / deferInstructionObservations=yes.

-- 01. Coverage AMM v4 finale.
SELECT
    entry_name,
    entry_kind,
    event_family,
    expected_db_target,
    proof_status,
    local_event_kind,
    discriminator_hex,
    observed_count,
    materialized_count,
    trade_count
FROM k_sol_dex_event_coverage_entries
WHERE decoder_code = 'raydium_amm_v4'
ORDER BY entry_kind, entry_name, discriminator_hex;

-- 02. Instruction observations AMM v4.
SELECT
    instruction_name,
    discriminator_hex,
    COUNT(*) AS observed_count,
    COUNT(DISTINCT signature) AS tx_count
FROM k_sol_instruction_observations
WHERE decoder_code = 'raydium_amm_v4'
GROUP BY instruction_name, discriminator_hex
ORDER BY observed_count DESC, instruction_name, discriminator_hex;

-- 03. Legacy swap générique interdit.
SELECT
    de.event_kind,
    COUNT(*) AS decoded_count,
    COUNT(te.id) AS trade_count
FROM k_sol_dex_decoded_events de
LEFT JOIN k_sol_trade_events te
    ON te.decoded_event_id = de.id
WHERE de.protocol_name = 'raydium_amm_v4'
  AND de.event_kind = 'raydium_amm_v4.swap'
GROUP BY de.event_kind;

-- 04. Aucun decoded AMM v4 sans coverage entry.
SELECT
    de.event_kind,
    COUNT(*) AS decoded_count
FROM k_sol_dex_decoded_events de
LEFT JOIN k_sol_dex_event_coverage_entries ce
    ON ce.decoder_code = 'raydium_amm_v4'
   AND ce.local_event_kind = de.event_kind
WHERE de.protocol_name = 'raydium_amm_v4'
  AND ce.id IS NULL
GROUP BY de.event_kind
ORDER BY decoded_count DESC, de.event_kind;

-- 05. Les observations AMM v4 doivent rester en discriminant 1 octet.
SELECT
    discriminator_hex,
    COUNT(*) AS observation_count,
    COUNT(DISTINCT signature) AS tx_count
FROM k_sol_instruction_observations
WHERE decoder_code = 'raydium_amm_v4'
  AND discriminator_hex IS NOT NULL
  AND length(discriminator_hex) > 2
GROUP BY discriminator_hex
ORDER BY observation_count DESC, discriminator_hex;

-- 06. Tous les discriminants officiels AMM v4 doivent être observés.
WITH expected(discriminator_hex, instruction_name) AS (
    VALUES
        ('00', 'raydium_amm_v4.initialize'),
        ('01', 'raydium_amm_v4.initialize2_pool'),
        ('02', 'raydium_amm_v4.monitor_step'),
        ('03', 'raydium_amm_v4.deposit'),
        ('04', 'raydium_amm_v4.withdraw'),
        ('05', 'raydium_amm_v4.migrate_to_open_book'),
        ('06', 'raydium_amm_v4.set_params'),
        ('07', 'raydium_amm_v4.withdraw_pnl'),
        ('08', 'raydium_amm_v4.withdraw_srm'),
        ('09', 'raydium_amm_v4.swap_base_in'),
        ('0a', 'raydium_amm_v4.pre_initialize'),
        ('0b', 'raydium_amm_v4.swap_base_out'),
        ('0c', 'raydium_amm_v4.simulate_info'),
        ('0d', 'raydium_amm_v4.admin_cancel_orders'),
        ('0e', 'raydium_amm_v4.create_config_account'),
        ('0f', 'raydium_amm_v4.update_config_account'),
        ('10', 'raydium_amm_v4.swap_base_in_v2'),
        ('11', 'raydium_amm_v4.swap_base_out_v2')
)
SELECT
    expected.discriminator_hex,
    expected.instruction_name
FROM expected
LEFT JOIN k_sol_instruction_observations io
    ON io.decoder_code = 'raydium_amm_v4'
   AND io.discriminator_hex = expected.discriminator_hex
WHERE io.id IS NULL
ORDER BY expected.discriminator_hex;

-- 07. Residual instruction_audit.
SELECT
    json_extract(payload_json, '$.discriminatorHex') AS discriminator_hex,
    COUNT(*) AS audit_count,
    COUNT(DISTINCT transaction_id) AS tx_count
FROM k_sol_dex_decoded_events
WHERE protocol_name = 'raydium_amm_v4'
  AND event_kind = 'raydium_amm_v4.instruction_audit'
GROUP BY discriminator_hex
ORDER BY audit_count DESC, discriminator_hex;

-- 08. Fallback upstream localement couvert.
SELECT
    json_extract(ug.payload_json, '$.upstreamDecoderCode') AS upstream_decoder_code,
    json_extract(ug.payload_json, '$.upstreamEntryName') AS entry_name,
    json_extract(ug.payload_json, '$.upstreamDiscriminatorHex') AS discriminator_hex,
    json_extract(ug.payload_json, '$.upstreamSourceRepo') AS source_repo,
    COUNT(*) AS fallback_count,
    COUNT(DISTINCT ug.transaction_id) AS tx_count
FROM k_sol_dex_decoded_events ug
JOIN k_sol_dex_event_coverage_entries ce
    ON ce.decoder_code = json_extract(ug.payload_json, '$.upstreamDecoderCode')
   AND ce.entry_name = json_extract(ug.payload_json, '$.upstreamEntryName')
   AND ce.discriminator_hex = json_extract(ug.payload_json, '$.upstreamDiscriminatorHex')
   AND ce.local_event_kind IS NOT NULL
   AND ce.local_event_kind <> ''
WHERE ug.protocol_name = 'upstream_git'
  AND ug.event_kind = 'upstream_git.instruction_match'
  AND json_extract(ug.payload_json, '$.upstreamDecoderCode') = 'raydium_amm_v4'
GROUP BY upstream_decoder_code, entry_name, discriminator_hex, source_repo
ORDER BY fallback_count DESC, entry_name;

-- 09. Non-swap safety : aucun non-swap ne doit produire de trade.
SELECT
    de.event_kind,
    ce.event_family,
    COUNT(*) AS decoded_count,
    COUNT(te.id) AS trade_count
FROM k_sol_dex_decoded_events de
LEFT JOIN k_sol_dex_event_coverage_entries ce
    ON ce.decoder_code = 'raydium_amm_v4'
   AND ce.local_event_kind = de.event_kind
LEFT JOIN k_sol_trade_events te
    ON te.decoded_event_id = de.id
WHERE de.protocol_name = 'raydium_amm_v4'
GROUP BY de.event_kind, ce.event_family
HAVING ce.event_family <> 'swap'
   AND COUNT(te.id) > 0
ORDER BY trade_count DESC, de.event_kind;

-- 10. Failed transaction safety : aucune failed tx ne doit être matérialisée en trade.
SELECT
    de.event_kind,
    COUNT(*) AS decoded_failed_count,
    COUNT(te.id) AS trade_count
FROM k_sol_dex_decoded_events de
JOIN k_sol_chain_transactions tx
    ON tx.id = de.transaction_id
LEFT JOIN k_sol_trade_events te
    ON te.decoded_event_id = de.id
WHERE de.protocol_name = 'raydium_amm_v4'
  AND tx.err_json IS NOT NULL
  AND tx.err_json <> ''
  AND tx.err_json <> 'null'
GROUP BY de.event_kind
HAVING COUNT(te.id) > 0
ORDER BY trade_count DESC, de.event_kind;

-- 11. Aucun successful non-materialized sans raison explicite.
SELECT
    de.event_kind,
    COUNT(*) AS unexplained_count
FROM k_sol_dex_decoded_events de
JOIN k_sol_chain_transactions tx
    ON tx.id = de.transaction_id
LEFT JOIN k_sol_trade_events te
    ON te.decoded_event_id = de.id
LEFT JOIN k_sol_liquidity_events le
    ON le.decoded_event_id = de.id
LEFT JOIN k_sol_pool_lifecycle_events pe
    ON pe.decoded_event_id = de.id
LEFT JOIN k_sol_fee_events fe
    ON fe.decoded_event_id = de.id
LEFT JOIN k_sol_pool_admin_events ae
    ON ae.decoded_event_id = de.id
LEFT JOIN k_sol_orderbook_events oe
    ON oe.decoded_event_id = de.id
LEFT JOIN k_sol_token_account_events tae
    ON tae.decoded_event_id = de.id
WHERE de.protocol_name = 'raydium_amm_v4'
  AND (
      tx.err_json IS NULL
      OR tx.err_json = ''
      OR tx.err_json = 'null'
  )
  AND te.id IS NULL
  AND le.id IS NULL
  AND pe.id IS NULL
  AND fe.id IS NULL
  AND ae.id IS NULL
  AND oe.id IS NULL
  AND tae.id IS NULL
  AND COALESCE(TRIM(json_extract(de.payload_json, '$.skipTradeReason')), '') = ''
  AND COALESCE(TRIM(json_extract(de.payload_json, '$.skipLiquidityReason')), '') = ''
  AND COALESCE(TRIM(json_extract(de.payload_json, '$.skipLifecycleReason')), '') = ''
  AND COALESCE(TRIM(json_extract(de.payload_json, '$.skipCatalogReason')), '') = ''
  AND de.event_kind NOT IN (
      'raydium_amm_v4.simulate_info'
  )
GROUP BY de.event_kind
ORDER BY unexplained_count DESC, de.event_kind;

-- 12. pre_initialize lifecycle audit minimal.
SELECT
    COUNT(*) AS decoded_success_count,
    COUNT(pe.id) AS lifecycle_count
FROM k_sol_dex_decoded_events de
JOIN k_sol_chain_transactions tx
    ON tx.id = de.transaction_id
LEFT JOIN k_sol_pool_lifecycle_events pe
    ON pe.decoded_event_id = de.id
WHERE de.protocol_name = 'raydium_amm_v4'
  AND de.event_kind = 'raydium_amm_v4.pre_initialize'
  AND (
      tx.err_json IS NULL
      OR tx.err_json = ''
      OR tx.err_json = 'null'
  );

-- 13. Dépôts : contexte catalogue pool/pair.
SELECT
    de.pool_account,
    COUNT(DISTINCT de.id) AS decoded_count,
    COUNT(DISTINCT le.id) AS liquidity_count,
    COUNT(DISTINCT p.id) AS pool_catalog_count,
    COUNT(DISTINCT pair.id) AS pair_catalog_count,
    GROUP_CONCAT(DISTINCT pair.id) AS pair_ids
FROM k_sol_dex_decoded_events de
LEFT JOIN k_sol_liquidity_events le
    ON le.decoded_event_id = de.id
LEFT JOIN k_sol_pools p
    ON p.address = de.pool_account
LEFT JOIN k_sol_pairs pair
    ON pair.pool_id = p.id
WHERE de.protocol_name = 'raydium_amm_v4'
  AND de.event_kind = 'raydium_amm_v4.deposit'
GROUP BY de.pool_account
ORDER BY decoded_count DESC, de.pool_account;

-- 14. Matérialisation single-target : aucun event AMM v4 ne doit alimenter deux tables métier principales.
SELECT
    de.event_kind,
    COUNT(DISTINCT de.id) AS decoded_count,
    COUNT(DISTINCT te.id) AS trade_count,
    COUNT(DISTINCT le.id) AS liquidity_count,
    COUNT(DISTINCT pe.id) AS lifecycle_count,
    COUNT(DISTINCT fe.id) AS fee_count,
    COUNT(DISTINCT ae.id) AS admin_count,
    COUNT(DISTINCT oe.id) AS orderbook_count,
    (
        CASE WHEN COUNT(DISTINCT te.id) > 0 THEN 1 ELSE 0 END
      + CASE WHEN COUNT(DISTINCT le.id) > 0 THEN 1 ELSE 0 END
      + CASE WHEN COUNT(DISTINCT pe.id) > 0 THEN 1 ELSE 0 END
      + CASE WHEN COUNT(DISTINCT fe.id) > 0 THEN 1 ELSE 0 END
      + CASE WHEN COUNT(DISTINCT ae.id) > 0 THEN 1 ELSE 0 END
      + CASE WHEN COUNT(DISTINCT oe.id) > 0 THEN 1 ELSE 0 END
    ) AS materialized_target_count
FROM k_sol_dex_decoded_events de
LEFT JOIN k_sol_trade_events te
    ON te.decoded_event_id = de.id
LEFT JOIN k_sol_liquidity_events le
    ON le.decoded_event_id = de.id
LEFT JOIN k_sol_pool_lifecycle_events pe
    ON pe.decoded_event_id = de.id
LEFT JOIN k_sol_fee_events fe
    ON fe.decoded_event_id = de.id
LEFT JOIN k_sol_pool_admin_events ae
    ON ae.decoded_event_id = de.id
LEFT JOIN k_sol_orderbook_events oe
    ON oe.decoded_event_id = de.id
WHERE de.protocol_name = 'raydium_amm_v4'
GROUP BY de.event_kind
HAVING materialized_target_count > 1
ORDER BY materialized_target_count DESC, de.event_kind;

-- 15. Résumé par table métier.
SELECT
    de.event_kind,
    COUNT(DISTINCT de.id) AS decoded_count,
    COUNT(DISTINCT te.id) AS trade_count,
    COUNT(DISTINCT le.id) AS liquidity_count,
    COUNT(DISTINCT pe.id) AS lifecycle_count,
    COUNT(DISTINCT fe.id) AS fee_count,
    COUNT(DISTINCT ae.id) AS admin_count,
    COUNT(DISTINCT oe.id) AS orderbook_count
FROM k_sol_dex_decoded_events de
LEFT JOIN k_sol_trade_events te
    ON te.decoded_event_id = de.id
LEFT JOIN k_sol_liquidity_events le
    ON le.decoded_event_id = de.id
LEFT JOIN k_sol_pool_lifecycle_events pe
    ON pe.decoded_event_id = de.id
LEFT JOIN k_sol_fee_events fe
    ON fe.decoded_event_id = de.id
LEFT JOIN k_sol_pool_admin_events ae
    ON ae.decoded_event_id = de.id
LEFT JOIN k_sol_orderbook_events oe
    ON oe.decoded_event_id = de.id
WHERE de.protocol_name = 'raydium_amm_v4'
GROUP BY de.event_kind
ORDER BY de.event_kind;

-- 16. Décision raydium_pool_v4 : aucune promotion runtime attendue en 0.7.51.
SELECT
    decoder_code,
    entry_name,
    local_event_kind,
    proof_status,
    observed_count,
    materialized_count
FROM k_sol_dex_event_coverage_entries
WHERE decoder_code = 'raydium_pool_v4'
ORDER BY entry_name;
