v0.1.0-pre.055
This commit is contained in:
@@ -18,3 +18,6 @@ TOKEN_2022_AUTHORITY=
|
|||||||
TOKEN_2022_FREEZE_AUTHORITY=
|
TOKEN_2022_FREEZE_AUTHORITY=
|
||||||
TOKEN_2022_DECIMALS=9
|
TOKEN_2022_DECIMALS=9
|
||||||
TOKEN_2022_TRANSFER_AMOUNT_RAW=1
|
TOKEN_2022_TRANSFER_AMOUNT_RAW=1
|
||||||
|
|
||||||
|
# Optional explicit environment file selection. Relative paths use the workspace root.
|
||||||
|
# KB_ENV_FILE=.env.local
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# file: Cargo.toml
|
# file: Cargo.toml
|
||||||
# version: 6
|
# version: 7
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "3"
|
resolver = "3"
|
||||||
@@ -38,7 +38,7 @@ chacha20poly1305 = { version = "^0.11", features = ["std", "stream"] }
|
|||||||
chrono = { version = "^0.4", features = ["serde"] }
|
chrono = { version = "^0.4", features = ["serde"] }
|
||||||
fs2 = { version = "^0.4", features = [] }
|
fs2 = { version = "^0.4", features = [] }
|
||||||
futures-util = { version = "^0.3", features = ["default", "futures-sink"] }
|
futures-util = { version = "^0.3", features = ["default", "futures-sink"] }
|
||||||
jsonschema = { version = "^0.48", features = [] }
|
jsonschema = { version = "^0.49", features = [] }
|
||||||
mpl-token-metadata = { version = "^5.1", features = ["serde"] }
|
mpl-token-metadata = { version = "^5.1", features = ["serde"] }
|
||||||
rand = { version = "^0.10", features = ["chacha", "serde", "std", "sys_rng"] }
|
rand = { version = "^0.10", features = ["chacha", "serde", "std", "sys_rng"] }
|
||||||
reqwest = { version = "^0.13", default-features = false, features = ["charset", "cookies", "deflate", "form", "gzip", "http2", "json", "multipart", "query", "rustls", "socks", "stream", "zstd"] }
|
reqwest = { version = "^0.13", default-features = false, features = ["charset", "cookies", "deflate", "form", "gzip", "http2", "json", "multipart", "query", "rustls", "socks", "stream", "zstd"] }
|
||||||
|
|||||||
561
KHADHROONY_BOT3_MIGRATION_CLOSURE_TODO.md
Normal file
561
KHADHROONY_BOT3_MIGRATION_CLOSURE_TODO.md
Normal file
@@ -0,0 +1,561 @@
|
|||||||
|
# Khadhroony Bot3 — Checklist de clôture de la migration
|
||||||
|
|
||||||
|
> **Périmètre :** clôturer la migration de `khadhroony-bot2` vers `khadhroony-bot3`, stabiliser `kb-app-demo-desktop` et valider l’intégration des crates consolidées.
|
||||||
|
>
|
||||||
|
> **Base de suivi :** `0.1.0-pre.055` et correctifs suivants.
|
||||||
|
>
|
||||||
|
> **Règle d’utilisation :** cocher chaque case uniquement après validation locale explicite. Les sous-cases constituent les critères d’acceptation de la tâche parente.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. État validé à ce jour
|
||||||
|
|
||||||
|
- [x] Les fenêtres historiques principales ont été portées dans `kb-app-demo-desktop`.
|
||||||
|
- [x] Les décodeurs, modèles, matérialiseurs et exécuteurs sont consommés depuis `kb-lib`.
|
||||||
|
- [x] `kb-store-core` et `kb-store-pg` ont été fusionnés dans `kb-store`.
|
||||||
|
- [x] `kb-program-ids` est une dépendance explicite du desktop.
|
||||||
|
- [x] `kb-pipeline-demo-scenarios` est une dépendance explicite du desktop.
|
||||||
|
- [x] Le pool WebSocket n’est plus initialisé au démarrage de l’application.
|
||||||
|
- [x] Le pool WebSocket est créé paresseusement à l’ouverture/utilisation de `demo_ws`.
|
||||||
|
- [x] La session WebSocket survit à la fermeture de la fenêtre `demo_ws`.
|
||||||
|
- [x] La réouverture de `demo_ws` récupère l’état de la session existante.
|
||||||
|
- [x] La clé `HELIUS_API_KEY` chargée depuis `.env` permet une connexion Helius réelle.
|
||||||
|
- [x] Les fenêtres dynamiques sont déclarées dans `vite.config.ts` et `capabilities/default.json`, sans être ajoutées à `tauri.conf.json`.
|
||||||
|
- [x] La permission de logging est attribuée aux fenêtres dynamiques.
|
||||||
|
- [x] Les balises HTML mal imbriquées qui rechargeaient `main.html` ont été corrigées.
|
||||||
|
- [x] Les routes de fichiers de logs consolidées produisent une arborescence cohérente.
|
||||||
|
- [x] L’audit Rust global est propre sur la base testée :
|
||||||
|
- `General Rust rule audit: clean`
|
||||||
|
- `Rust export completeness audit: 0 candidate(s)`
|
||||||
|
- `Khadhroony workspace rule audit: clean`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Corriger immédiatement les deux afficheurs non JSON
|
||||||
|
|
||||||
|
### 1.1 Fenêtre HTTP JSON-RPC
|
||||||
|
|
||||||
|
- [ ] Remplacer le `@andypf/json-viewer` du bloc **Résultat** par un `<textarea readonly>`.
|
||||||
|
- [ ] Conserver le résultat RPC sous sa forme textuelle exacte, sans supposer qu’il s’agit toujours de JSON.
|
||||||
|
- [ ] Ajouter exactement un bouton **Copier** utilisant le presse-papiers.
|
||||||
|
- [ ] Ajouter exactement un bouton **Effacer**.
|
||||||
|
- [ ] S’assurer que l’effacement vide également le buffer TypeScript interne.
|
||||||
|
- [ ] Donner au textarea une hauteur fixe et un scroll interne.
|
||||||
|
- [ ] Tester successivement :
|
||||||
|
- réponse JSON structurée ;
|
||||||
|
- valeur scalaire ;
|
||||||
|
- chaîne simple ;
|
||||||
|
- erreur RPC ;
|
||||||
|
- résultat vide.
|
||||||
|
|
||||||
|
### 1.2 Fenêtre WebSocket
|
||||||
|
|
||||||
|
- [ ] Remplacer le `@andypf/json-viewer` du bloc **Messages** par un `<textarea readonly>`.
|
||||||
|
- [ ] Conserver les messages sous forme de journal texte append-only.
|
||||||
|
- [ ] Ajouter exactement un bouton **Copier**.
|
||||||
|
- [ ] Ajouter exactement un bouton **Effacer**.
|
||||||
|
- [ ] S’assurer que l’effacement vide le buffer en mémoire et le contenu visible.
|
||||||
|
- [ ] Donner au textarea une hauteur fixe et un scroll interne.
|
||||||
|
- [ ] Vérifier que la réouverture de la fenêtre restaure :
|
||||||
|
- l’état de connexion ;
|
||||||
|
- les abonnements actifs ;
|
||||||
|
- le statut de session ;
|
||||||
|
- le journal conservé, si cette conservation est voulue.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Audit global des composants Copier / Effacer
|
||||||
|
|
||||||
|
- [ ] Rechercher tous les boutons statiques et boutons injectés dynamiquement :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find kb-app-demo-desktop/frontend \
|
||||||
|
-type f \( -name '*.html' -o -name '*.ts' \) -print0 |
|
||||||
|
xargs -0 grep -nE 'Copier|Effacer|clipboard|app-log-clear|attach.*controls'
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Pour chaque bloc de journal ou résultat textuel, garantir **une seule** paire Copier/Effacer.
|
||||||
|
- [ ] Interdire la coexistence de boutons HTML statiques et de boutons ajoutés par `frontend_log.ts` sur le même composant.
|
||||||
|
- [ ] Vérifier au minimum :
|
||||||
|
- `demo_backfill` ;
|
||||||
|
- `demo_core_extraction` ;
|
||||||
|
- `demo_http` ;
|
||||||
|
- `demo_ws` ;
|
||||||
|
- `demo_decode_replay` ;
|
||||||
|
- `demo_execution_solana_core` ;
|
||||||
|
- `demo_execution_spl` ;
|
||||||
|
- fenêtres SQL ;
|
||||||
|
- configuration.
|
||||||
|
- [ ] Ajouter un test frontend ou une vérification statique qui échoue lorsqu’un conteneur reçoit plusieurs groupes de contrôles.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Uniformiser la position des journaux généraux
|
||||||
|
|
||||||
|
- [x] Le journal du Backfill HTTP est placé hors de l’accordéon.
|
||||||
|
- [x] Le journal d’Extraction core est placé hors de l’accordéon.
|
||||||
|
- [ ] Vérifier que tous les journaux généraux restent visibles lorsque les sections de paramètres sont repliées.
|
||||||
|
- [ ] Déplacer hors des accordéons tout journal général encore imbriqué dans une section de paramètres.
|
||||||
|
- [ ] Conserver dans les accordéons uniquement les sorties strictement liées à une opération ou à un sous-panneau particulier.
|
||||||
|
- [ ] Documenter une règle UI :
|
||||||
|
- paramètres et formulaires dans les accordéons ;
|
||||||
|
- journal global et résultat principal sous l’accordéon ;
|
||||||
|
- hauteur fixe avec scroll ;
|
||||||
|
- une seule paire Copier/Effacer.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Politique JSON commune
|
||||||
|
|
||||||
|
- [ ] Utiliser `@andypf/json-viewer` uniquement lorsque la valeur affichée est garantie comme JSON.
|
||||||
|
- [ ] Utiliser un textarea readonly pour :
|
||||||
|
- journaux ;
|
||||||
|
- flux de messages ;
|
||||||
|
- texte brut ;
|
||||||
|
- réponses dont le format varie ;
|
||||||
|
- erreurs non structurées.
|
||||||
|
- [ ] Centraliser la création et la mise à jour des viewers JSON dans un helper TypeScript commun.
|
||||||
|
- [ ] Appliquer une hauteur fixe à tous les viewers JSON.
|
||||||
|
- [ ] Appliquer un scroll interne au-delà de la hauteur maximale.
|
||||||
|
- [ ] Éviter qu’un collapse contenant du JSON agrandisse indéfiniment `.card-body`.
|
||||||
|
- [ ] Vérifier tous les viewers présents dans :
|
||||||
|
- Configuration ;
|
||||||
|
- SQL diagnostics ;
|
||||||
|
- Decode replay ;
|
||||||
|
- exécutions ;
|
||||||
|
- autres vues structurées.
|
||||||
|
- [ ] Prévoir une règle pour les valeurs JSON invalides : fallback texte, sans crash de la fenêtre.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Stabiliser les fenêtres SQL
|
||||||
|
|
||||||
|
### 5.1 Layout
|
||||||
|
|
||||||
|
- [ ] Restaurer une disposition pleine largeur pour :
|
||||||
|
- SQL diagnostics ;
|
||||||
|
- PostgreSQL raw ;
|
||||||
|
- PostgreSQL core.
|
||||||
|
- [ ] Ne pas splitter les tableaux principaux en deux colonnes.
|
||||||
|
- [ ] Réserver les colonnes uniquement aux petits panneaux synthétiques si nécessaire.
|
||||||
|
- [ ] Supprimer le scroll horizontal global de la page.
|
||||||
|
- [ ] Autoriser un scroll horizontal local uniquement dans `.table-responsive` lorsque réellement nécessaire.
|
||||||
|
- [ ] Vérifier que le listing des tables utilise toute la largeur disponible.
|
||||||
|
- [ ] Comparer le rendu avec Bot2 pour éviter une régression fonctionnelle ou ergonomique.
|
||||||
|
|
||||||
|
### 5.2 Navigation et IPC
|
||||||
|
|
||||||
|
- [x] Les balises de navbar mal fermées ont été corrigées.
|
||||||
|
- [ ] Vérifier chaque bouton et chaque onglet des quatre fenêtres SQL.
|
||||||
|
- [ ] Confirmer qu’aucune action ne recharge `main.html`.
|
||||||
|
- [ ] Confirmer qu’aucun clic ne déclenche une navigation implicite via un `<a>` parent.
|
||||||
|
- [ ] Vérifier les formulaires et boutons sans `type="button"` susceptibles de soumettre un formulaire.
|
||||||
|
- [ ] Revalider les appels IPC lors de rechargements Vite, sans considérer l’ancien défaut comme actif s’il n’est plus reproductible.
|
||||||
|
|
||||||
|
### 5.3 Initialisation PostgreSQL
|
||||||
|
|
||||||
|
- [ ] Décider définitivement quand exécuter `initialize_postgres_schema_for_startup` :
|
||||||
|
- au démarrage avec compte rendu dans le splash ; ou
|
||||||
|
- à la première ouverture d’une fenêtre SQL.
|
||||||
|
- [ ] Supprimer le code mort si l’initialisation de démarrage est abandonnée.
|
||||||
|
- [ ] Sinon, brancher réellement :
|
||||||
|
- `initialize_postgres_schema_for_startup` ;
|
||||||
|
- `emit_sql_startup_table_report` ;
|
||||||
|
- `emit_sql_startup_error` ;
|
||||||
|
- `emit_sql_startup_splash`.
|
||||||
|
- [ ] Ne pas conserver durablement des helpers publics ou `pub(crate)` inutilisés.
|
||||||
|
- [ ] Ajouter des tests de schéma présent, incomplet et inaccessible.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Corriger les échecs Metaplex Token Metadata
|
||||||
|
|
||||||
|
### 6.1 Constat issu des logs `pre.055`
|
||||||
|
|
||||||
|
- [x] Le pipeline sélectionne correctement le décodeur `metadata_metaplex_token_metadata`.
|
||||||
|
- [x] Le programme canonique est reconnu :
|
||||||
|
|
||||||
|
```text
|
||||||
|
metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s
|
||||||
|
```
|
||||||
|
|
||||||
|
- [x] L’archive analysée contient **10 échecs** explicites de validation de comptes :
|
||||||
|
- **8** `create_metadata_account_v3 account 1 has invalid signer/writable flags` ;
|
||||||
|
- **2** `transfer account 1 has invalid signer/writable flags`.
|
||||||
|
|
||||||
|
### 6.2 Diagnostic à effectuer
|
||||||
|
|
||||||
|
- [ ] Extraire pour chaque transaction échouée :
|
||||||
|
- signature ;
|
||||||
|
- slot ;
|
||||||
|
- chemin d’instruction ;
|
||||||
|
- instruction outer/inner ;
|
||||||
|
- données brutes ;
|
||||||
|
- liste ordonnée des comptes ;
|
||||||
|
- flags signer/writable réellement reconstruits.
|
||||||
|
- [ ] Vérifier si `account 1` désigne :
|
||||||
|
- l’index dans les comptes de l’instruction ;
|
||||||
|
- l’index global du message ;
|
||||||
|
- un index décalé par le program ID ;
|
||||||
|
- un compte issu d’une Address Lookup Table.
|
||||||
|
- [ ] Vérifier la reconstruction des flags pour :
|
||||||
|
- comptes statiques ;
|
||||||
|
- comptes chargés par ALT ;
|
||||||
|
- instructions internes ;
|
||||||
|
- comptes dupliqués ;
|
||||||
|
- invocation CPI.
|
||||||
|
- [ ] Comparer les contrats du décodeur avec :
|
||||||
|
- l’IDL officiel `token_metadata.json` ;
|
||||||
|
- les builders/generated instructions Metaplex ;
|
||||||
|
- des transactions mainnet réelles.
|
||||||
|
- [ ] Vérifier si les contraintes imposées sont trop strictes pour les CPI, notamment lorsqu’un programme appelant transmet un compte avec des privilèges supérieurs ou différents.
|
||||||
|
- [ ] Distinguer clairement :
|
||||||
|
- compte absent ;
|
||||||
|
- nombre de comptes invalide ;
|
||||||
|
- signer manquant ;
|
||||||
|
- writable manquant ;
|
||||||
|
- privilège supplémentaire acceptable ;
|
||||||
|
- privilège incompatible.
|
||||||
|
|
||||||
|
### 6.3 Correctif et tests
|
||||||
|
|
||||||
|
- [ ] Corriger la matrice de comptes de `create_metadata_account_v3`.
|
||||||
|
- [ ] Corriger la matrice de comptes de `transfer`.
|
||||||
|
- [ ] Ajouter les transactions réelles de l’archive comme fixtures bornées ou vecteurs synthétiques équivalents.
|
||||||
|
- [ ] Ajouter un test de CPI pour chaque instruction concernée.
|
||||||
|
- [ ] Ajouter un test avec Address Lookup Table si applicable.
|
||||||
|
- [ ] Ajouter un test où un compte possède un privilège supérieur acceptable.
|
||||||
|
- [ ] Ajouter un test qui refuse réellement un signer/writable manquant.
|
||||||
|
- [ ] Rejouer les signatures échouées avec `forceReplay=true`.
|
||||||
|
- [ ] Obtenir `failed=0` pour les cas désormais supportés.
|
||||||
|
- [ ] Classer en `Unsupported` plutôt qu’en `Failed` toute variante volontairement hors périmètre mais valide sur chaîne.
|
||||||
|
- [ ] Vérifier la matérialisation après correction du décodage.
|
||||||
|
|
||||||
|
### 6.4 Observabilité du décodeur
|
||||||
|
|
||||||
|
- [ ] Enrichir le diagnostic avec :
|
||||||
|
- nom du rôle attendu ;
|
||||||
|
- index du compte ;
|
||||||
|
- pubkey ;
|
||||||
|
- flags attendus ;
|
||||||
|
- flags observés ;
|
||||||
|
- contexte outer/inner.
|
||||||
|
- [ ] Afficher ces diagnostics dans la fenêtre Decode replay.
|
||||||
|
- [ ] Ajouter un bouton Copier pour les diagnostics détaillés.
|
||||||
|
- [ ] Ne pas exposer de données sensibles dans les logs.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. IDL Metaplex Token Metadata
|
||||||
|
|
||||||
|
- [ ] Placer le snapshot officiel dans le workspace :
|
||||||
|
|
||||||
|
```text
|
||||||
|
idls/metaplex_token_metadata.metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s.json
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Conserver le fichier source/provenance associé.
|
||||||
|
- [ ] Documenter :
|
||||||
|
- URL officielle ;
|
||||||
|
- commit ou SHA du blob ;
|
||||||
|
- version IDL `1.14.0` ;
|
||||||
|
- program ID canonique.
|
||||||
|
- [ ] Ajouter un script de rafraîchissement déterministe.
|
||||||
|
- [ ] Ajouter un test vérifiant que l’IDL est du JSON valide.
|
||||||
|
- [ ] Ajouter un test comparant les discriminants couverts par le décodeur avec l’IDL.
|
||||||
|
- [ ] Ne pas utiliser l’IDL comme seule source normative lorsque le programme ou les generated builders divergent.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Configuration `.env` et ordre de résolution
|
||||||
|
|
||||||
|
### 8.1 `kb-config`
|
||||||
|
|
||||||
|
- [x] `dotenvy` appartient à `kb-config`, pas au desktop.
|
||||||
|
- [ ] Vérifier l’API publique finale et ses noms.
|
||||||
|
- [ ] Appliquer et tester l’ordre :
|
||||||
|
1. environnement déjà présent dans le processus ;
|
||||||
|
2. fichier explicitement indiqué par `KB_ENV_FILE` ;
|
||||||
|
3. `.env` à la racine du workspace ;
|
||||||
|
4. fallback `${VAR:-fallback}` ;
|
||||||
|
5. variable non résolue conservée ou erreur selon le contrat du champ.
|
||||||
|
- [ ] Garantir qu’un `.env` ne remplace jamais une variable déjà injectée par le shell, systemd, Docker, CI ou IDE.
|
||||||
|
- [ ] Définir le comportement si `KB_ENV_FILE` pointe vers un fichier absent.
|
||||||
|
- [ ] Définir le comportement si `.env` est absent.
|
||||||
|
- [ ] Définir le comportement des lignes invalides.
|
||||||
|
- [ ] Interdire l’impression de valeurs secrètes dans les diagnostics.
|
||||||
|
- [ ] Ajouter des tests isolés et sérialisés pour éviter les collisions d’environnement global entre tests.
|
||||||
|
|
||||||
|
### 8.2 `kb-app-demo-desktop`
|
||||||
|
|
||||||
|
- [ ] Retirer toute lecture ou tout chargement `.env` résiduel du desktop.
|
||||||
|
- [ ] Ne conserver que l’appel à l’API de chargement de `kb-config`.
|
||||||
|
- [ ] Afficher dans la fenêtre Configuration la provenance des sources sans afficher les secrets :
|
||||||
|
- environnement processus ;
|
||||||
|
- fichier `.env` chargé ;
|
||||||
|
- fallback ;
|
||||||
|
- non résolu.
|
||||||
|
- [ ] Vérifier que l’application démarre sans clé Helius.
|
||||||
|
- [ ] Vérifier que l’utilisation d’un endpoint Helius sans clé produit une erreur ciblée.
|
||||||
|
- [x] Vérifier qu’une clé valide dans `.env` permet HTTP et WebSocket Helius.
|
||||||
|
|
||||||
|
### 8.3 `kb-pipeline-demo-scenarios`
|
||||||
|
|
||||||
|
- [ ] Ne pas dépendre directement de `dotenvy`.
|
||||||
|
- [ ] Centraliser l’initialisation par `kb-config` lorsque les scénarios sont lancés directement.
|
||||||
|
- [ ] Réduire progressivement les appels directs `std::env::var`.
|
||||||
|
- [ ] Introduire des structures typées pour :
|
||||||
|
- SPL Token classique ;
|
||||||
|
- ATA ;
|
||||||
|
- Token-2022 ;
|
||||||
|
- ElGamal Registry ;
|
||||||
|
- scénarios Solana Core.
|
||||||
|
- [ ] Permettre l’injection des valeurs dans les tests sans modifier l’environnement global.
|
||||||
|
- [ ] Vérifier que les variables externes historiques `TOKEN_2022_*` peuvent rester nommées ainsi, tout en utilisant `token2022` dans les modules Rust internes.
|
||||||
|
|
||||||
|
### 8.4 Tâche ultérieure `kb-store`
|
||||||
|
|
||||||
|
- [ ] **À reporter :** décider si les chemins/URLs de base sont entièrement résolus par `kb-config` avant construction de `kb-store`.
|
||||||
|
- [ ] Ne pas faire charger `.env` directement par `kb-store`.
|
||||||
|
- [ ] Prévoir une configuration typée déjà résolue pour PostgreSQL et les futures bases.
|
||||||
|
- [ ] Étudier la séparation future des targets de logs `kb-store.core` et `kb-store.postgres`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Cycle de vie WebSocket
|
||||||
|
|
||||||
|
- [x] Aucun pool WebSocket au démarrage général.
|
||||||
|
- [x] Création paresseuse lors du premier accès.
|
||||||
|
- [x] Pool conservé dans `AppState`.
|
||||||
|
- [x] Fermeture de `demo_ws` sans fermeture de la session.
|
||||||
|
- [x] Récupération du statut à la réouverture.
|
||||||
|
- [ ] Utiliser `disconnect_demo_ws_app_state` lors de la fermeture globale de l’application.
|
||||||
|
- [ ] Ne pas l’appeler lors de la simple destruction de `demo_ws`.
|
||||||
|
- [ ] Tester la fermeture explicite depuis la fenêtre.
|
||||||
|
- [ ] Tester le timeout de session.
|
||||||
|
- [ ] Tester la fermeture de l’application avec session et abonnements actifs.
|
||||||
|
- [ ] Vérifier qu’aucune tâche Tokio ni relay ne reste suspendu après arrêt.
|
||||||
|
- [ ] Éliminer le warning `dead_code` de façon fonctionnelle, sans supprimer le hook requis.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Menu principal et cohérence visuelle
|
||||||
|
|
||||||
|
- [ ] Réordonner définitivement le dropdown des fenêtres selon les groupes suivants :
|
||||||
|
1. Configuration ;
|
||||||
|
2. Transport : HTTP, WebSocket, Backfill ;
|
||||||
|
3. Pipeline : Extraction core, Decode replay ;
|
||||||
|
4. SQL : diagnostics, raw, core, replay ;
|
||||||
|
5. Exécution : Solana Core, SPL.
|
||||||
|
- [ ] Ajouter des séparateurs ou titres de groupes non cliquables.
|
||||||
|
- [ ] Vérifier que chaque fenêtre possède le logo non cliquable.
|
||||||
|
- [ ] Vérifier particulièrement `demo_execution_solana_core`.
|
||||||
|
- [ ] Garder les descriptions longues dans le contenu principal et non dans la navbar.
|
||||||
|
- [ ] Vérifier les deux textes :
|
||||||
|
- « System Program uniquement — simulation-first et replay post-exécution » ;
|
||||||
|
- « Memo, SPL Token classique, Token-2022 et ATA — simulation-first et replay post-exécution ».
|
||||||
|
- [ ] Uniformiser titres, sous-titres, marges et hauteurs de navbar.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. Vérifier les options de la fenêtre Exécution SPL
|
||||||
|
|
||||||
|
- [ ] Auditer toutes les valeurs de `demo_execution_spl.html`.
|
||||||
|
- [ ] Vérifier leur correspondance exacte avec les parsers et enums Rust.
|
||||||
|
- [ ] Remplacer les valeurs internes historiques `token_2022` par `token2022` lorsqu’elles ne constituent pas un contrat externe.
|
||||||
|
- [ ] Conserver uniquement les variables d’environnement externes `TOKEN_2022_*` si elles sont déjà documentées et utilisées.
|
||||||
|
- [ ] Vérifier chaque scénario :
|
||||||
|
- Memo v4 ;
|
||||||
|
- SPL Token classique ;
|
||||||
|
- Token-2022 ;
|
||||||
|
- ATA.
|
||||||
|
- [ ] Vérifier que Memo v1 et v3 restent non exécutables.
|
||||||
|
- [ ] Vérifier les scénarios publics Token-2022 réellement supportés par l’exécuteur.
|
||||||
|
- [ ] Retirer ou désactiver toute option UI sans implémentation réelle.
|
||||||
|
- [ ] Ajouter un test qui compare la liste HTML/TypeScript avec l’inventaire Rust exposé.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. Façades consolidées et nomenclature
|
||||||
|
|
||||||
|
- [ ] Exécuter une recherche uniquement sur les fichiers Rust :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find kb-app-demo-desktop -type f -name '*.rs' -print0 |
|
||||||
|
xargs -0 grep -nE 'kb_store_pg|kb_store_core|kb_model|kb_decoder_|kb_materializer_|kb_executor_|token_2022|_2022'
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Aucun ancien crate Bot2 ne doit subsister.
|
||||||
|
- [ ] Tous les modèles, décodeurs, matérialiseurs et exécuteurs doivent passer par `kb-lib`.
|
||||||
|
- [ ] Tout le stockage doit passer par `kb-store`.
|
||||||
|
- [ ] Les modules Rust internes utilisent `token2022`, jamais `token_2022`.
|
||||||
|
- [ ] Les constantes utilisent `SPL_TOKEN2022_*` selon la nomenclature de `kb-program-ids`.
|
||||||
|
- [ ] Les variables d’environnement externes `TOKEN_2022_*` peuvent rester.
|
||||||
|
- [ ] Vérifier tous les `export_to` uniquement dans les `.rs` :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find kb-config kb-lib kb-app-demo-desktop \
|
||||||
|
-type f -name '*.rs' -print0 |
|
||||||
|
xargs -0 grep -n 'export_to'
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Corriger les chemins TS-RS résiduels qui imitent des anciens noms de crates.
|
||||||
|
- [ ] Supprimer les fichiers de bindings orphelins générés par les anciens chemins.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. Logging
|
||||||
|
|
||||||
|
- [x] La sortie console compacte est de nouveau active.
|
||||||
|
- [x] Les routes consolidées produisent une arborescence cohérente.
|
||||||
|
- [ ] Vérifier la console pour chaque profil configuré.
|
||||||
|
- [ ] Vérifier qu’aucune route n’utilise un ancien target Bot2.
|
||||||
|
- [ ] Vérifier l’absence de dossiers vides créés pour des targets inexistants.
|
||||||
|
- [ ] Ajouter un test de complétude des routes par rapport aux targets publics actuels.
|
||||||
|
- [ ] Vérifier la cohérence tiret/underscore entre target et répertoire.
|
||||||
|
- [ ] Décider ultérieurement si `kb-store` doit produire :
|
||||||
|
- `kb-store/core` ;
|
||||||
|
- `kb-store/postgres`.
|
||||||
|
- [ ] Ne pas traiter cette séparation comme bloquante pour la clôture de la migration.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 14. Nettoyage des warnings Rust
|
||||||
|
|
||||||
|
- [ ] Résoudre le warning `DemoDecodeReplayProgressPayload` inutilisé par un usage réel ou un ajustement de visibilité justifié.
|
||||||
|
- [ ] Résoudre le warning `initialize_postgres_schema_for_startup` inutilisé après décision sur l’initialisation SQL.
|
||||||
|
- [ ] Résoudre le warning `disconnect_demo_ws_app_state` inutilisé en le branchant sur l’arrêt global.
|
||||||
|
- [ ] Résoudre les helpers SQL privés inutilisés en les utilisant ou en les supprimant si le flux est abandonné.
|
||||||
|
- [ ] Ne pas supprimer une fonction prévue uniquement pour faire taire un warning sans décision architecturale.
|
||||||
|
- [ ] Obtenir `cargo test -p kb-app-demo-desktop` sans warning propre au code applicatif.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 15. Clippy et macros Tauri
|
||||||
|
|
||||||
|
- [ ] Traiter en dernier les erreurs `clippy::question_mark_used` provenant des expansions `#[tauri::command]` async.
|
||||||
|
- [ ] Confirmer qu’aucun `?` interdit n’existe dans le code source métier.
|
||||||
|
- [ ] Choisir une solution localisée et documentée :
|
||||||
|
- allowance au niveau du module adaptateur Tauri ; ou
|
||||||
|
- configuration ciblée pour le code généré ; ou
|
||||||
|
- exception d’audit explicite pour les macros externes.
|
||||||
|
- [ ] Ne pas rendre les commandes synchrones uniquement pour satisfaire Clippy.
|
||||||
|
- [ ] Ne pas désactiver le lint à l’échelle du workspace.
|
||||||
|
- [ ] Ajouter une note dans `RUST_RULES.md` expliquant l’exception du code généré Tauri.
|
||||||
|
- [ ] Obtenir finalement :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo clippy --all-targets
|
||||||
|
```
|
||||||
|
|
||||||
|
sans erreur.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 16. Validation fonctionnelle de chaque fenêtre
|
||||||
|
|
||||||
|
- [ ] Splash : affiche uniquement les composants réellement initialisés au démarrage, puis est détruit.
|
||||||
|
- [ ] Main : menu ordonné, tous les liens fonctionnels.
|
||||||
|
- [ ] Configuration : viewers JSON bornés, provenance de configuration lisible, secrets masqués.
|
||||||
|
- [ ] HTTP : méthodes, paramètres, résultat texte, Copier/Effacer.
|
||||||
|
- [ ] WebSocket : connexion, abonnements multiples, restauration, messages texte, déconnexion.
|
||||||
|
- [ ] Backfill : anciens/nouveaux historiques, annulation, journal permanent, résultat.
|
||||||
|
- [ ] SQL diagnostics : pleine largeur, refresh, erreurs.
|
||||||
|
- [ ] SQL raw : pleine largeur, tables et compteurs.
|
||||||
|
- [ ] SQL core : pleine largeur, tables et compteurs.
|
||||||
|
- [ ] SQL replay : filtres, DataTables, CSV, onglets.
|
||||||
|
- [ ] Extraction core : campagne, annulation, journal permanent.
|
||||||
|
- [ ] Decode replay : 7 décodeurs, matérialiseurs, diagnostics, annotations.
|
||||||
|
- [ ] Exécution Solana Core : simulation, envoi contrôlé, replay post-exécution.
|
||||||
|
- [ ] Exécution SPL : Memo v4, Token, Token-2022, ATA.
|
||||||
|
- [ ] Fermeture et réouverture répétées de toutes les fenêtres dynamiques.
|
||||||
|
- [ ] Vérification qu’aucune fenêtre dynamique ne démarre automatiquement.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 17. Tests de scénarios hors Tauri
|
||||||
|
|
||||||
|
- [ ] Déplacer ou dupliquer les scénarios métier importants dans `kb-pipeline-demo-scenarios`.
|
||||||
|
- [ ] Couvrir Solana Core.
|
||||||
|
- [ ] Couvrir Memo v4.
|
||||||
|
- [ ] Couvrir SPL Token classique.
|
||||||
|
- [ ] Couvrir ATA.
|
||||||
|
- [ ] Couvrir Token-2022.
|
||||||
|
- [ ] Couvrir ElGamal Registry lorsque validable.
|
||||||
|
- [ ] Couvrir Metaplex Token Metadata.
|
||||||
|
- [ ] Tester sans démarrer Tauri.
|
||||||
|
- [ ] Tester avec configurations injectées plutôt qu’avec environnement global lorsque possible.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 18. Sécurité des secrets et fichiers locaux
|
||||||
|
|
||||||
|
- [ ] Vérifier que `.env` est ignoré par Git.
|
||||||
|
- [ ] Conserver `.env.example` versionné sans secret.
|
||||||
|
- [ ] Vérifier l’historique Git pour s’assurer qu’aucune clé Helius réelle n’a été ajoutée.
|
||||||
|
- [ ] Masquer les valeurs sensibles dans les logs et dans la fenêtre Configuration.
|
||||||
|
- [ ] Ne jamais inclure `.env` dans les archives delta.
|
||||||
|
- [ ] Ajouter une validation de démarrage qui signale la présence/absence d’une clé sans l’afficher.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 19. Validation technique finale
|
||||||
|
|
||||||
|
- [ ] `cargo fmt --all`
|
||||||
|
- [ ] `cargo check -p kb-config`
|
||||||
|
- [ ] `cargo test -p kb-config`
|
||||||
|
- [ ] `cargo check -p kb-pipeline-demo-scenarios`
|
||||||
|
- [ ] `cargo test -p kb-pipeline-demo-scenarios`
|
||||||
|
- [ ] `cargo check -p kb-app-demo-desktop`
|
||||||
|
- [ ] `cargo test -p kb-app-demo-desktop`
|
||||||
|
- [ ] `cargo check --workspace`
|
||||||
|
- [ ] `cargo test --workspace`
|
||||||
|
- [ ] `python3 scripts/audit_rust_workspace_rules.py`
|
||||||
|
- [ ] `cargo clippy --all-targets` après traitement de l’exception Tauri.
|
||||||
|
- [ ] `cargo tauri dev -c kb-app-demo-desktop/tauri.conf.json`
|
||||||
|
- [ ] Vérification manuelle de toutes les fenêtres.
|
||||||
|
- [ ] Vérification réelle HTTP Helius.
|
||||||
|
- [ ] Vérification réelle WebSocket Helius.
|
||||||
|
- [ ] Rejeu Metaplex avec `failed=0` sur les cas corrigés.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 20. Documentation et clôture
|
||||||
|
|
||||||
|
- [ ] Mettre à jour `README.md` avec l’architecture Bot3 finale.
|
||||||
|
- [ ] Mettre à jour `ROADMAP.md` avec les points réellement clôturés et les reports.
|
||||||
|
- [ ] Mettre à jour `CHANGELOG.md` avec toutes les prereleases et fixes.
|
||||||
|
- [ ] Documenter la politique `.env` et l’ordre de résolution.
|
||||||
|
- [ ] Documenter le cycle de vie HTTP/WebSocket.
|
||||||
|
- [ ] Documenter les fenêtres dynamiques, Vite et capabilities.
|
||||||
|
- [ ] Documenter les conventions de viewers JSON et de journaux texte.
|
||||||
|
- [ ] Documenter l’IDL Metaplex et sa provenance.
|
||||||
|
- [ ] Documenter les tâches reportées :
|
||||||
|
- résolution de configuration de base dans `kb-store` ;
|
||||||
|
- séparation des logs `kb-store.core` / `kb-store.postgres` ;
|
||||||
|
- améliorations non bloquantes.
|
||||||
|
- [ ] Préparer le prompt complet de la session suivante.
|
||||||
|
- [ ] Livrer le dernier delta de migration.
|
||||||
|
- [ ] Effectuer le commit Git de clôture.
|
||||||
|
- [ ] Taguer la prerelease ou version de clôture selon la convention retenue.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 21. Critères de clôture obligatoires
|
||||||
|
|
||||||
|
La migration ne peut être déclarée terminée que lorsque toutes les conditions suivantes sont satisfaites :
|
||||||
|
|
||||||
|
- [ ] Toutes les fenêtres historiques requises sont présentes et fonctionnelles.
|
||||||
|
- [ ] Aucun ancien crate Bot2 n’est référencé.
|
||||||
|
- [ ] Aucune erreur de compilation ou de test.
|
||||||
|
- [ ] Audits Rust et workspace propres.
|
||||||
|
- [ ] Aucun warning applicatif non justifié.
|
||||||
|
- [ ] `.env` est centralisé dans `kb-config` et sa priorité est testée.
|
||||||
|
- [ ] HTTP et WebSocket Helius fonctionnent avec une clé locale non versionnée.
|
||||||
|
- [ ] Les erreurs Metaplex observées sont corrigées ou classées explicitement et correctement.
|
||||||
|
- [ ] Les fenêtres SQL n’ont ni navigation involontaire ni layout régressif.
|
||||||
|
- [ ] Chaque journal/résultat texte possède une seule paire Copier/Effacer.
|
||||||
|
- [ ] Les viewers JSON sont bornés en hauteur et réservés au JSON réel.
|
||||||
|
- [ ] Le cycle de vie WebSocket est validé jusqu’à l’arrêt global.
|
||||||
|
- [ ] La documentation de clôture et le prompt suivant sont livrés.
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,208 +0,0 @@
|
|||||||
<!-- file: CHANGELOG.md -->
|
|
||||||
<!-- version: 26 -->
|
|
||||||
|
|
||||||
# Changelog
|
|
||||||
|
|
||||||
Ce fichier est réservé aux versions validées. Les changements non validés restent décrits dans `ROADMAP.md` ou `RULES.md`.
|
|
||||||
|
|
||||||
## 0.0.1 — projet vide
|
|
||||||
|
|
||||||
Initialisation du dépôt comme point de départ vide. Cette version sert uniquement de repère historique avant la création du squelette modulaire.
|
|
||||||
|
|
||||||
## 0.0.2 — squelette stabilisé
|
|
||||||
|
|
||||||
Validation du squelette initial de `khadhroony-bot2` : workspace Rust modulaire, règles de développement, nomenclature des surfaces, registres de programmes, configuration multi-profils, couche d'exécution réservée, décodeurs/exécuteurs/matérialisateurs réservés, documentation de cadrage, prompts de session et application Tauri de démonstration en squelette. Cette version devient la base propre avant le développement `0.1.x` consacré à `kb_logging` et `kb_config`.
|
|
||||||
|
|
||||||
## 0.1.0 — `kb_logging` réel
|
|
||||||
|
|
||||||
Validation du jalon `kb_logging` : API publique minimale, initialisation `tracing_subscriber`, routes console, fichier humain, fichier JSON et fichier erreurs, filtrage par target et niveau, nettoyage ANSI des fichiers pour les messages issus de WebView Tauri, support des globs `crate.*` et `crate::*`, et couverture unitaire renforcée. Validation locale effectuée : `cargo test -p kb_logging` avec 14 tests passés et `cargo clippy -p kb_logging --all-targets` sans erreur. `cargo fmt` n'est pas retenu comme validation obligatoire du jalon, car la configuration `rustfmt.toml` contient des options nightly non applicables sur stable et le formatage courant est géré depuis Eclipse.
|
|
||||||
|
|
||||||
## 0.1.1 — `kb_config` typé et validé
|
|
||||||
|
|
||||||
Validation du jalon `kb_config` : configuration JSON multi-profils avec un seul profil actif, schéma `config/schema.config.json` validé via `jsonschema`, désérialisation typée, validation métier des profils, endpoints HTTP JSON-RPC et WebSocket Solana standard, listeners standards, sorties de logging configurables, stores PostgreSQL/SQLite, wallet, exécution et sections de démonstration. Les placeholders de clés restent directement dans les URLs et les champs runtime hors périmètre avant `v1.x` sont refusés par le schéma. Les exports TS-rs suivent la convention `../frontend/ts/bindings/kb_config/settings/<Type>.ts`. Validation locale effectuée : `cargo test --tests -p kb_config` avec 35 tests passés, dont les tests générateurs TS-rs `export_bindings_*`, et `cargo clippy` annoncé sans erreur pour le jalon.
|
|
||||||
|
|
||||||
## 0.1.2 — liaison `kb_logging`, `kb_config` et démo Tauri
|
|
||||||
|
|
||||||
Validation du jalon d’intégration Tauri : `kb_app_demo` charge le profil actif via `kb_config`, initialise `kb_logging` depuis cette configuration, conserve un `AppState` global, garde `demo_config` comme fenêtre de démonstration isolée et réémet les logs frontend vers `tracing` avec des targets statiques. La fenêtre principale rend le README workspace en HTML via `markdown-it`, expose un dropdown de démos, et la fenêtre configuration affiche le profil actif, la configuration complète et le schéma JSON avec un viewer JSON interactif. Le verrou mono-instance est appliqué uniquement dans `kb_app_demo/src/main.rs` afin de préserver l’entrée mobile par `kb_app_demo_lib::run()`. Le provider Rustls par défaut est initialisé dans la librairie pour desktop et mobile. Le splashscreen est aligné sur le modèle de `khadhroony-bobobot/kb_demo_app`, avec fade-in/fade-out, durée minimale extensible et attente initiale avant fade-in pour éviter l’apparition instantanée. `kb_core` expose maintenant l’erreur et le résultat communs sous `kb_core::Error` et `kb_core::Result`. Validation locale effectuée : `cargo test -p kb_core` avec 2 tests passés, `cargo test -p kb_config` avec 35 tests passés, `cargo test -p kb_logging` avec 14 tests passés, `cargo test -p kb_app_demo` avec 12 tests passés, `cargo clippy --all-targets` sans erreur et validation visuelle via `cargo tauri dev -c kb_app_demo/tauri.conf.json`.
|
|
||||||
|
|
||||||
## 0.1.3 — clients HTTP/WS Solana standard, rôles et pools
|
|
||||||
|
|
||||||
Validation du jalon RPC initial : `kb_rpc` expose les contrats JSON-RPC 2.0 partagés, le routage par rôle et `request_kind`, les clients HTTP JSON-RPC et WebSocket Solana standard, ainsi que les pools HTTP/WS par rôle. `kb_app_demo` ajoute les fenêtres dédiées `demo_http` et `demo_ws`, les listes contrôlées de rôles et méthodes, le refresh explicite des pools, le profil `mainnet` Helius, la connexion WebSocket persistante conservée dans `AppState`, les subscriptions multiples sur une même socket, l’unsubscribe individuel, la déconnexion globale à l’arrêt de l’application et le throttling des notifications WebSocket vers la WebView pour éviter les freezes sur les programmes très bavards. Les transports gRPC, Helius enhanced WebSocket, Helius gRPC et LaserStream restent hors périmètre avant les versions ultérieures. Validation locale effectuée : `cargo test -p kb_rpc` avec 39 tests passés, `cargo test -p kb_app_demo` avec 28 tests passés, `cargo clippy --all-targets` sans erreur, et validation visuelle des démos HTTP/WS via `cargo tauri dev -c kb_app_demo/tauri.conf.json`.
|
|
||||||
|
|
||||||
## 0.2.0 — conventions PostgreSQL et contrats DB
|
|
||||||
|
|
||||||
Validation du jalon de cadrage stockage : conventions PostgreSQL définies autour du schéma courant/default du profil, généralement `public`, sans espaces applicatifs séparés, et convention de tables Solana `kb_sol_<domain>_<name>` avec les domaines `raw`, `core`, `obs`, `decode`, `mat`, `catalog`, `agg`, `ops` et `wallet` intégrés au nom de table. Les règles SQL de base sont documentées pour `id`, `created_at`, `updated_at`, `slot`, `signature`, `program_id`, `raw_json` et `payload_json`, avec index minimaux et contraintes strictes mais réversibles. Les responsabilités de `kb_store_core` et `kb_store_pg` sont clarifiées, avec séparation `entities/`, `dtos/`, `queries/` et `repositories/`, et interdiction de placer des structures métier ou DB dans les requêtes. Les migrations historiques de brouillon sont neutralisées afin de ne pas créer d'espace PostgreSQL applicatif ni de table qualifiée par espace logique. Validation locale effectuée : `cargo test -p kb_config` avec 35 tests passés, `cargo test -p kb_app_demo` avec 28 tests passés et `cargo clippy --all-targets` sans erreur. `kb_store_core` et `kb_store_pg` ne disposent pas encore de tests à ce stade documentaire.
|
|
||||||
|
|
||||||
## 0.2.1 — contrats `kb_store_core` et replay instruction-level
|
|
||||||
|
|
||||||
Validation du jalon de contrats storage : `kb_store_core` expose les types communs backend-agnostiques pour pagination, healthcheck, migrations, erreurs de stockage, DTOs applicatifs, entities proches SQL et traits repositories sans implémentation PostgreSQL. Les contrats couvrent le raw RPC et WebSocket, le cycle de vie raw `Full` / `Compacted` / `Archived` / `Purged`, les états de traitement raw, la signature optionnelle des notifications WebSocket, la déduplication par `notification_key`, le lien futur optionnel notification vers transaction canonique, ainsi que le replay par instruction. Le replay est défini comme un scheduling au niveau instruction, mais le décodage reçoit un contexte extrait complet via `MdCoreInstructionReplayInput` : instruction ciblée, account keys, logs, balance changes et contexte transactionnel minimal. Les repositories restent abstraits et ne créent encore ni pool PostgreSQL, ni migration SQL réelle. Validation locale effectuée : `cargo test -p kb_store_core` avec 28 tests passés et `cargo clippy --all-targets` sans avertissement. Les validations précédentes du jalon ont également confirmé `kb_store_pg` sans test actif, `kb_config` avec 35 tests passés et `kb_app_demo` avec 28 tests passés.
|
|
||||||
|
|
||||||
## 0.2.2 — infrastructure PostgreSQL minimale
|
|
||||||
|
|
||||||
Validation du jalon d'infrastructure PostgreSQL : `kb_store_pg` expose maintenant une première implémentation réelle avec options de connexion, pool `sqlx::PgPool`, construction depuis la configuration active, masquage du DSN pour les diagnostics, healthcheck `SELECT 1`, lecture du schema courant, lecture de la version PostgreSQL et snapshot de migrations non destructif. La stratégie de migrations reste volontairement cadrée sans créer les tables Solana lourdes, qui sont reportées à `0.2.3` pour le raw store minimal. Les validateurs de noms de tables imposent la convention `kb_sol_<domain>_<name>` et refusent les schemas explicites. Validation locale effectuée : `cargo test -p kb_store_pg` avec 11 tests passés, test PostgreSQL réel optionnel `optional_postgres_healthcheck_from_env` validé avec `KB_POSTGRES_TEST_URL=postgres://solana:solana@localhost:5432/solana`, `cargo test -p kb_store_core` avec 28 tests passés, `cargo test -p kb_config` avec 35 tests passés, `cargo test -p kb_app_demo` avec 28 tests passés et `cargo clippy --all-targets` sans avertissement après remplacement local de l'exception `allow` par `expect` sur l'incompatibilité connue `async_trait` / `clippy::implicit_return`.
|
|
||||||
|
|
||||||
## 0.2.3 — raw store Solana minimal
|
|
||||||
|
|
||||||
Validation du jalon raw store minimal : `kb_store_pg` crée et initialise les deux premières tables Solana réelles, `kb_sol_raw_rpc_transactions` et `kb_sol_raw_ws_notifications`, sans créer de schema PostgreSQL applicatif explicite. Le raw RPC est inséré de façon idempotente par signature, les notifications WebSocket sont dédupliquées par `notification_key`, la signature des notifications reste optionnelle et le lien vers la transaction RPC canonique est préparé pour les étapes suivantes. Les tables conservent les champs de cycle de vie `retention_state`, `processing_state`, `processed_at` et `processing_reason`, avec `raw_json` nullable côté SQL afin de permettre les futures politiques `compacted`, `archived` et `purged` sans migration cassante. Les requêtes et l'implémentation PostgreSQL de `RawTransactionStore` couvrent les insertions, lookup de signature, lookup de notification et marquage lifecycle. Validation locale effectuée : `cargo test -p kb_store_pg` avec 21 tests passés, incluant le test PostgreSQL réel optionnel `optional_postgres_raw_store_roundtrip_from_env` avec `KB_POSTGRES_TEST_URL=postgres://solana:solana@localhost:5432/solana`, `cargo test -p kb_store_core` avec 28 tests passés, `cargo test -p kb_config` avec 35 tests passés, `cargo test -p kb_app_demo` avec 28 tests passés et `cargo clippy --all-targets` sans avertissement. Une correction locale du test raw PostgreSQL a été intégrée pour appeler directement `test_signature()` depuis le module de test.
|
|
||||||
|
|
||||||
## 0.2.4 — core Solana normalisé minimal
|
|
||||||
|
|
||||||
Validation du jalon core store minimal : `kb_store_pg` crée et initialise maintenant les tables core `kb_sol_core_transactions`, `kb_sol_core_account_keys`, `kb_sol_core_instructions`, `kb_sol_core_inner_instructions`, `kb_sol_core_logs` et `kb_sol_core_balance_changes`, en complément du raw store `0.2.3`, sans schema PostgreSQL applicatif explicite. Les migrations et l'initializer utilisent des noms SQL préfixés et explicites pour les contraintes et index : `pk_`, `fk_`, `ck_`, `ux_` et `ix_`. L'initialisation raw/core est sérialisée par un verrou PostgreSQL `pg_advisory_xact_lock` afin d'éviter les courses concurrentes pendant les tests ou les démarrages parallèles. `CoreTransactionStore` dispose de l'implémentation PostgreSQL minimale pour insérer les transactions core, account keys, instructions, inner instructions, logs et deltas de balances, puis reconstruire `MdCoreInstructionReplayInput` pour les futurs décodeurs. Le script de maintenance `kb_store_pg/maintenance/drop_raw_core_store.sql` permet de réinitialiser explicitement les tables raw/core locales dans l'ordre inverse des dépendances. Validation locale effectuée : `KB_POSTGRES_TEST_URL=postgres://solana:solana@localhost:5432/solana cargo test -p kb_store_pg -- --nocapture` avec 30 tests passés, création vérifiée des 8 tables dans PostgreSQL, réinitialisation validée via le script de maintenance, puis `cargo clippy --all-targets` sans avertissement. Le worker d'extraction raw RPC vers core, les observations et le ledger ops sont conservés pour les jalons suivants.
|
|
||||||
|
|
||||||
## 0.2.5 — diagnostics SQL PostgreSQL dans `kb_app_demo`
|
|
||||||
|
|
||||||
Validation du jalon diagnostics SQL : `kb_app_demo` ajoute les fenêtres `demo_sql_diag`, `demo_sql_pg_raw` et `demo_sql_pg_core` pour inspecter en lecture seule l’état PostgreSQL courant. Le démarrage Tauri tente l’initialisation raw/core lorsque `database.postgres.auto_initialize_schema` est actif, journalise les tables créées ou déjà présentes via le splashscreen et `tracing`, puis les fenêtres exposent le profil actif, le backend, le DSN masqué, le schema courant, le healthcheck, l’état migrations et les statistiques de tables raw/core. Les payloads JSON des trois fenêtres utilisent le viewer interactif déjà utilisé par `demo_config`, sans ajouter de nouvelle dépendance npm. Le jalon ne lance ni extracteur raw RPC vers core, ni décodage, ni matérialisation ; ces traitements restent reportés à `0.3.x`. Validation locale effectuée : `cargo test -p kb_store_pg` avec 30 tests passés, `cargo test -p kb_config` avec 35 tests passés, `cargo test -p kb_app_demo` avec 32 tests passés, `cargo clippy --all-targets` sans avertissement, et validation visuelle des trois fenêtres via `cargo tauri dev -c kb_app_demo/tauri.conf.json`.
|
|
||||||
|
|
||||||
## 0.3.0 — cadrage Agave local et sources temps réel
|
|
||||||
|
|
||||||
Validation du jalon de cadrage `0.3.x` : la phase ingestion/backfill/extraction raw vers core est reportée à `0.4.x`, tandis que `0.3.x` devient une phase d’expérimentation Agave local non votant et de stratégie live source. Le jalon documente le profil manuel `agave_local_research`, la commande de départ `agave-validator`, les probes RPC/WS attendus, les mesures ledger/accounts/CPU/RAM/réseau/lag, les règles de fallback vers les providers externes et les critères de décision avant `0.4.x`. Le profil Agave reste désactivé par défaut afin de préserver `mainnet_research` comme base stable, et aucune ingestion de production, aucun backfill historique, aucun décodage DEX, aucune matérialisation et aucune opération de trading ne sont introduits dans ce jalon. Validation locale du delta `0.3.0-pre.001` confirmée par l’utilisateur avant mise à jour du changelog.
|
|
||||||
|
|
||||||
## 0.3.1 — transaction canonique et observations d’acquisition
|
|
||||||
|
|
||||||
Validation du jalon de stockage canonique : `kb_sol_raw_transactions` conserve désormais une transaction source-indépendante par signature avec `canonical_json`, `canonical_json_hash` et `canonical_format_version`, tandis que `kb_sol_obs_transaction_observations` conserve uniquement les informations de provenance, méthode, session, timestamps, taille, statut et erreur sans dupliquer le payload complet. La lignée core utilise `raw_transaction_id`; les DTOs, entities, repositories, requêtes et diagnostics Tauri ont été alignés. La migration réelle depuis le schéma `0.2.x` a été contrôlée sur PostgreSQL 17.10 : les anciennes tables `kb_sol_raw_rpc_transactions` et `kb_sol_raw_ws_notifications` sont absentes, les tables canoniques sont présentes et les colonnes actives portent les nouveaux noms. Après cette validation, les fichiers SQL ont été consolidés en une baseline propre ne contenant que `0001_canonical_transaction_store.sql` et `0002_core_store.sql`; les fichiers SQL actifs n’embarquent plus les anciennes définitions de tables. Validation locale effectuée : `cargo test -p kb_app_demo` avec 32 tests passés, `cargo test -p kb_store_core` avec 30 tests passés, `KB_POSTGRES_TEST_URL=postgres://solana:solana@localhost:5432/solana cargo test -p kb_store_pg -- --nocapture` avec 32 tests passés, `cargo clippy --all-targets` sans avertissement, démarrage Tauri validé et diagnostics des huit tables raw/obs/core confirmés. Les fixtures PostgreSQL de test ont été nettoyées manuellement après validation.
|
|
||||||
|
|
||||||
## 0.3.2 — contrat canonique et adaptateur HTTP
|
|
||||||
|
|
||||||
Validation du jalon transactionnel canonique : `kb_model` expose désormais un modèle source-indépendant couvrant les transactions legacy et version 0, le message, les comptes statiques et chargés par Address Lookup Tables, les instructions externes et internes, les logs, le statut et les erreurs, les frais, compute units et cost units, les balances SOL et SPL/Token-2022, les rewards, les return data et le block time lorsqu’ils sont disponibles. Les signatures et clés publiques restent en base58, les données d’instruction sont normalisées en base64, les montants SPL bruts sont canonicalisés sans perte et la sérialisation déterministe trie récursivement les objets JSON avant calcul du hash SHA-256. `kb_rpc` fournit l’adaptateur `getTransaction` JSON-RPC et l’interface commune préparant les futurs adaptateurs Helius WebSocket et Yellowstone gRPC dans la crate existante, tandis que `kb_store_core::RawTransactionInsert::from_canonical` relie le modèle au store canonique. Les fixtures offline couvrent legacy/v0, succès/échec, ALT, CPI, SPL Token et Token-2022, et les formes fournisseur équivalentes produisent le même hash. Validation locale effectuée : `cargo test -p kb_model` avec 23 tests passés, `cargo test -p kb_rpc` avec 48 tests passés, `cargo test -p kb_store_core` avec 31 tests passés, `KB_POSTGRES_TEST_URL=postgres://solana:solana@localhost:5432/solana cargo test -p kb_store_pg -- --nocapture` avec 32 tests passés, puis `cargo clippy --all-targets` sans avertissement après ajout des retours explicites imposés par `clippy::implicit_return`. Les fixtures PostgreSQL du roundtrip ont été nettoyées manuellement après validation.
|
|
||||||
|
|
||||||
## 0.3.3 — backfill HTTP gratuit et `demo_backfill`
|
|
||||||
|
|
||||||
Validation du jalon de backfill HTTP : `kb_rpc` expose désormais `getSignaturesForAddress` avec pagination `before` / `until`, tandis que `getTransaction` alimente le modèle canonique sans conserver durablement le payload fournisseur. `kb_pipeline` orchestre les campagnes de signatures explicites et les recherches avant ou après une signature pour un programme, un token ou un pool, avec déduplication, limites de pages, reprise exportable, concurrence, temporisation, retries bornés, arrêt coopératif et journalisation détaillée. Le parcours `after` utilise la borne RPC `until`, des pages pouvant atteindre 1 000 signatures et une sélection bornée en mémoire afin de ne conserver que les `X` signatures directement postérieures à l’ancre dans l’historique de l’adresse. `kb_app_demo` ajoute la fenêtre `demo_backfill`, organisée en accordéons Bootstrap 5, avec paramètres communs, textarea de signatures, formulaires programme/token/pool, journal, résumé et commande d’arrêt. Chaque transaction complète est insérée une seule fois dans `kb_sol_raw_transactions`; chaque tentative d’acquisition produit une observation légère dans `kb_sol_obs_transaction_observations`, tandis que les résultats `missing` et `failed` ne créent aucun faux payload canonique.
|
|
||||||
|
|
||||||
La correction finale de l’arrêt coopératif remplace la création globale des futures par une file bornée à la concurrence effective, distingue les candidats sélectionnés, démarrés, terminés, annulés et non démarrés, et calcule `resume_before_signature` depuis le dernier préfixe contigu réellement terminé. Une campagne réelle de 500 candidats a validé l’arrêt avec 7 candidats démarrés, 3 terminés, 4 annulés et 493 non démarrés, sans journalisation artificielle des candidats restants. Validation locale effectuée : `cargo test -p kb_rpc` avec 54 tests passés, `cargo test -p kb_pipeline` avec 10 tests passés, `cargo test -p kb_store_core` avec 31 tests passés, `cargo test -p kb_store_pg` avec 32 tests passés, `cargo test -p kb_app_demo` avec 38 tests passés et `cargo clippy --all-targets` sans avertissement. Les campagnes Tauri réelles ont validé les signatures explicites, programme avant/après, token avant/après et pool avant/après ; le cas `program_after` a parcouru 5 516 signatures indexées avant de sélectionner les 5 signatures les plus proches de l’ancre. Les diagnostics PostgreSQL ont confirmé 62 transactions canoniques et 62 observations, sans alimentation prématurée des tables core, dont l’extraction reste prévue pour `0.3.4`.
|
|
||||||
|
|
||||||
## 0.3.4 — extraction canonique vers core et clôture de la fondation `0.3.x`
|
|
||||||
|
|
||||||
Validation du jalon d’extraction structurelle : `kb_pipeline` transforme les transactions canoniques en graphes core atomiques comprenant transactions, account keys statiques et ALT, instructions outer et inner à chemins stables, logs reliés prudemment et deltas SOL/SPL Token/Token-2022. `kb_store_core` et `kb_store_pg` exposent et implémentent les contrats de persistance, le ledger versionné `kb_sol_ops_processing_ledger`, le skip par version/hash, le force replay et le rollback complet. `kb_app_demo` ajoute `demo_core_extraction` et le navigateur read-only `demo_sql_replay_candidates` avec filtres, sélection, copie et exports CSV sous `data/exports_csv/`; `kb_program_ids` fournit un registre énumérable de 182 programmes. Les transactions Solana échouées restent extractibles et seront décodables comme observations d’intention ou d’échec, sans être matérialisées automatiquement comme mutations réussies. Validation réelle effectuée sur PostgreSQL 17.10 : 70 transactions extraites sans erreur, sept contrôles d’intégrité sans anomalie, replay normal de 14 signatures entièrement ignoré, force replay des mêmes 14 signatures sans duplication, second replay entièrement ignoré, cardinalité finale de 70 transactions core et ledger final de 70 succès pour 84 tentatives. Validation locale finale : `cargo test -p kb_pipeline` avec 24 tests passés, `KB_POSTGRES_TEST_URL=... cargo test -p kb_store_pg -- --nocapture` avec 39 tests passés dont le rollback/replay corrigé, `cargo test -p kb_app_demo` avec 60 tests passés, `cargo test -p kb_program_ids` avec 2 tests passés et `cargo clippy --all-targets` sans avertissement. L’ancien jalon `0.3.5` est absorbé dans cette version ; la suite active devient `0.4.0` pour l’infrastructure commune de décodage et de matérialisation.
|
|
||||||
|
|
||||||
## 0.4.0 — infrastructure commune de décodage et de matérialisation
|
|
||||||
|
|
||||||
Validation du socle commun de replay contextualisé : `kb_decoder_api` et `kb_materializer_api` travaillent sur les inputs core complets, `kb_pipeline` sélectionne uniquement les programmes compatibles avec les processors activés, effectue un dispatch déterministe par programme et chemin d’instruction, persiste atomiquement couverture, ledger, événements décodés et sorties matérialisées, et applique le skip par processor/version/hash. Le force replay est autorisé uniquement avec des signatures explicites ou avec l’autorisation opérateur « toutes les signatures » bornée par les filtres et la limite. La matérialisation est refusée lorsqu’aucun matérialiseur n’est enregistré. Le classifieur `solana_native_classifier` déclare les 18 surfaces natives/runtime/loaders/précompiles connues sans produire de faux décodage.
|
|
||||||
|
|
||||||
`kb_app_demo` ajoute `demo_decode_replay`, ses diagnostics decode/ledger/couverture et les contrôles de replay normal, force replay ciblé, replay global explicitement autorisé, concurrence bornée et arrêt coopératif. Chaque campagne possède un `campaign_id` propagé par spans jusqu’au pipeline, au store PostgreSQL et au décodeur. Les migrations raw/core/decode sont appliquées une seule fois au démarrage Tauri ; les commandes de démo réutilisent ensuite le schéma initialisé. Les validations frontend du backfill bloquent localement les requêtes incomplètes sans produire de faux événements backend `ERROR`.
|
|
||||||
|
|
||||||
Validation locale finale : `cargo test -p kb_config` avec 36 tests passés, `cargo test -p kb_pipeline` avec 41 tests passés, `KB_POSTGRES_TEST_URL=postgres://solana:solana@localhost:5432/solana_test cargo test -p kb_store_pg -- --nocapture` avec 44 tests passés, `cargo test -p kb_app_demo` avec 75 tests passés et `cargo clippy --all-targets` sans avertissement. Les campagnes Tauri réelles ont validé neuf skips version/hash, neuf force replays ciblés, un second skip cohérent, un replay global strictement limité à cinq inputs, l’annulation puis le redémarrage d’une campagne, et la corrélation complète des traces. Le correctif final d’annulation garantit `started + not_started = selected` et `completed = started`; une campagne réelle a terminé avec 382 inputs sélectionnés, 45 démarrés/terminés, 337 non démarrés, 45 dispatchs `unsupported`, aucun unmatched, aucun échec et aucun événement dans `errors.jsonl`. La couverture PostgreSQL confirme 18 déclarations natives, 382 observations Compute Budget reconnues sans erreur et 94 observations System reconnues sans erreur. `0.4.1` devient le jalon actif pour le décodage maximal des programmes Solana natifs, loaders et précompiles.
|
|
||||||
|
|
||||||
## 0.4.1 — programmes Solana natifs, loaders, précompiles et matérialisations natives
|
|
||||||
|
|
||||||
Validation du jalon `0.4.1` : `kb_decoder_solana_core` couvre désormais les programmes Solana natifs/runtime, historiques, loaders, précompiles et surfaces ZK explicitement incluses dans le périmètre. Le registre exécutable natif contient 18 surfaces après reclassification de `StakeConfig11111111111111111111111111111111` comme compte historique non exécutable et ajout du stateless Slashing Program `S1ashing11111111111111111111111111111111111` observé dans Agave `v4.1.1` derrière feature gate. Les surfaces décodées incluent System, Vote, Stake, Config, Compute Budget, Address Lookup Table, Feature, ZK ElGamal Proof, l’ancien ZK Token Proof historique/no-op, les loaders Native/BPF v1/v2/Upgradeable/v4, Ed25519, secp256k1, secp256r1 et Slashing. SPL Memo, SPL Token, Token-2022, Stake Pool, Single Pool, Account Compression, Noop et SPL Name Service restent réservés aux jalons suivants.
|
|
||||||
|
|
||||||
Le jalon a étendu le contrat de replay instructionnel avec les instructions outer ordonnées afin de résoudre les références inter-instructions des précompiles et du profil Compute Budget. Les décodeurs bornent les offsets, tailles, compteurs, références d’instructions, comptes requis et payloads suffixes sans recalcul cryptographique pour les signatures ou preuves ZK. L’ancien `solana-zk-token-sdk` déprécié a été retiré ; le miroir ZK Token historique repose maintenant sur une table wire locale auditée, sans dépendance directe à `bincode`.
|
|
||||||
|
|
||||||
Les matérialisations natives sont clôturées au niveau instructionnel stable. `kb_materializer_lifecycle` projette Address Lookup Table, lifecycle des loaders, révocation Feature, durable nonce, comptes System create/allocate, contextes ZK ElGamal et rapports Slashing. `kb_materializer_admin` projette assignations System, écritures Config opaques et changements d’autorité Loader. `kb_materializer_compliance_audit` projette écritures/copies de bytecode Loader et profils Compute Budget transactionnels agrégés. `kb_materializer_staking` projette les intentions commitées Stake/Vote : comptes, autorités, lockup, délégation, désactivation, split, merge, retraits, move stake/lamports, identité Vote, commission, vote state et dépôt de rewards. Les sorties ne prétendent pas reconstruire les snapshots finaux de comptes, les sysvars historiques, les crédits Vote cumulés, l’activation Stake par epoch, les unités compute consommées ou les frais finaux runtime.
|
|
||||||
|
|
||||||
`kb_app_demo` enregistre les matérialiseurs natifs `solana_native_lifecycle`, `solana_native_admin`, `solana_native_compliance_audit` et `solana_native_staking`. Les profils de logging montent à 53 routes avec fichiers dédiés pour les crates opérationnelles ajoutées. `demo_backfill` accepte maintenant les modes `program_latest`, `token_latest` et `pool_latest` : une recherche « avant, plus anciennes » sans ancre commence sur les signatures les plus récentes, tandis que la direction « après, plus récentes » conserve une ancre obligatoire.
|
|
||||||
|
|
||||||
Les validations utilisateur finales confirment : `kb_program_ids` 5 tests, `kb_decoder_solana_core` 114 tests, `kb_materializer_lifecycle` 16 tests, `kb_materializer_admin` 7 tests, `kb_materializer_compliance_audit` 7 tests, `kb_materializer_staking` 8 tests, `kb_config` 36 tests, `kb_pipeline` 45 tests, `kb_store_pg` 45 tests avec PostgreSQL réel, `kb_app_demo` 78 tests et `cargo clippy --all-targets` sans avertissement. Le correctif de sérialisation test-only des tests PostgreSQL réels élimine l’interblocage intermittent observé lors des tests optionnels concurrents.
|
|
||||||
|
|
||||||
Les campagnes mainnet ciblées validées couvrent notamment : System 817 inputs décodés avec 258 sorties et 52 refus attendus sur transactions échouées ; Config 96/96 avec 96 sorties admin ; Stake 448/448 avec 447 sorties et un refus attendu ; Vote 600/600 avec 600 sorties ; Compute Budget 2 746/2 746 avec 1 603 profils transactionnels matérialisés ; ZK ElGamal 151/151 avec 139 sorties de contexte ; ALT 104/104 avec 104 sorties lifecycle ; Slashing sans corpus observable, validé par sources officielles et fixtures synthétiques. Tous ces replays se terminent avec `unmatched = 0`, `failedInputs = 0`, `unsupported = 0` et journaux `error.jsonl` vides dans les archives fournies.
|
|
||||||
|
|
||||||
La suite active devient `0.4.2` : infrastructure d’exécution et `kb_executor_solana_core`, avec séparation stricte entre plan, simulation, signature, envoi et validation post-exécution. Les exécuteurs SPL suivront ensuite la politique décodeur maximal → matérialisateurs → exécuteur limité par opération.
|
|
||||||
|
|
||||||
## 0.4.2 — infrastructure d’exécution native et RPC Solana standard
|
|
||||||
|
|
||||||
Validation du jalon d’exécution native. `kb_execution_api`, `kb_execution_safety`, `kb_execution_solana`, `kb_wallet`, `kb_executor_solana_core`, `kb_rpc` et `kb_pipeline` séparent explicitement intent, plan, politique, lecture stateful, simulation, signature, envoi, confirmation et validation post-exécution. Le wallet temporaire de laboratoire reste confiné à Localnet/Devnet ; dry-run et simulation sont obligatoires par défaut, les plafonds de dépense/frais sont vérifiés et Mainnet reste désactivé sans politique et confirmation explicites.
|
|
||||||
|
|
||||||
`kb_executor_solana_core` couvre 18 surfaces natives avec 109 opérations appelables : System, Compute Budget, Address Lookup Table, précompiles Ed25519/secp256k1/secp256r1, Config, Feature, Slashing, ZK ElGamal, Stake, Vote, Loader v3 et Loader v4. BPF Loader v1/v2, Native Loader et l’ancien ZK Token Proof sont classés sans builder client ; Stake `Redelegate` reste historique `decode-only`. Chaque builder est comparé à un encodeur officiel ou à un layout wire audité. La matrice `docs/NATIVE_SOLANA_EXECUTION_MATRIX.json` est vérifiée par un test Rust contre les 109 codes compilés. `kb_decoder_solana_core` conserve l’égalité exacte avec les 18 Program IDs natifs et 121 déclarations de couverture.
|
|
||||||
|
|
||||||
Le préflight stateful de `kb_pipeline` inspecte ALT, Config, Feature, Slashing et les contextes ZK ElGamal sur Localnet/Devnet et retourne `NotRequired`, `Ready` ou `Blocked`. Les opérations administratives non validées réellement par un scénario cluster restent derrière ce garde-fou, hors de l’UI et sans activation Mainnet. Le parcours Devnet représentatif System transfer a été validé avec un wallet persistant préfinancé et 1 000 000 lamports : simulation exacte, signature, envoi, confirmation, `getTransaction`, insertion canonique, extraction core et decode replay ciblé ont réussi.
|
|
||||||
|
|
||||||
`kb_rpc` expose des contrats propres et configurables pour les 52 méthodes HTTP standard et les neuf paires WebSocket standard. Les options sont composables sans exposer les DTO Agave. `WsSession` gère multiplexage, unsubscribe, timeout, reconnexion bornée et réabonnement. `blockSubscribe`, `slotsUpdatesSubscribe` et `voteSubscribe` sont activables par endpoint ; un rejet serveur indiquant une méthode absente ou non activée désactive automatiquement la capacité pour la session. `kb_app_demo` ne contient plus la boucle de transport WebSocket.
|
|
||||||
|
|
||||||
La frontière Tauri/TS-rs a été corrigée pour ne plus transmettre de `bigint` dans les payloads JSON actifs. Les identifiants WebSocket sont contrôlés contre `Number.isSafeInteger` et les limites du navigateur SQL sont validées avant l’invocation backend. Les logs réels confirment les souscriptions/désabonnements WebSocket et le garde-fou de changement d’endpoint avec session active.
|
|
||||||
|
|
||||||
Validation finale fournie par l’utilisateur : `kb_program_ids` 5 tests, `kb_decoder_solana_core` 116, `kb_executor_solana_core` 88, `kb_execution_api` 22, `kb_execution_safety` 15, `kb_execution_solana` 12, `kb_rpc` 113, `kb_pipeline` 56, `kb_config` 41, `kb_app_demo` 88 et `kb_store_pg` 45 avec PostgreSQL réel. Le test Devnet opt-in et le replay post-exécution sont réussis, `cargo clippy --all-targets` est propre et `cargo tauri dev` démarre avec Vite et initialise correctement PostgreSQL. Aucun jalon suivant n’est ouvert par cette clôture.
|
|
||||||
|
|
||||||
## 0.4.3 — SPL Memo v1, v3 et v4
|
|
||||||
|
|
||||||
Validation complète de la surface SPL Memo. `kb_decoder_spl_memo` reconnaît exactement les Program IDs v1, v3 et v4, décode le payload UTF-8 brut, sa longueur et son SHA-256, conserve les comptes ordonnés et leurs flags, distingue les règles historiques de signataires, les chemins outer/inner, les transactions réussies ou échouées et les tentatives invalides sans produire de faux état commité. La matrice machine-readable `docs/SPL_MEMO_MATRIX.json` relie les contrats officiels, les fixtures synthétiques et le corpus Mainnet réel des trois générations.
|
|
||||||
|
|
||||||
`kb_materializer_transaction_annotations` projette uniquement les Memo réussis et commités dans la famille `transaction_annotation`, avec texte borné, génération, Program ID, signataires vérifiés, provenance et clé d’idempotence. Les comptes complets et diagnostics d’audit restent dans le decode. La persistance réutilise `kb_sol_mat_events` et le ledger commun sans nouvelle table ; `demo_decode_replay` expose un journal typé et borné filtrable par signature.
|
|
||||||
|
|
||||||
`kb_executor_spl_memo` fournit les intents typés v1/v3/v4 et construit les trois générations avec `spl-memo-interface 2.1.0`, payload exact et signataires readonly ordonnés. La bibliothèque reste universelle sur les clusters ; simulation obligatoire, dry-run par défaut, plafond de frais, autorisation opérateur et politiques Mainnet appartiennent à l’infrastructure commune. Le parcours Memo v4 Devnet réutilise wallet, RPC, safety, transaction Solana, confirmation, hydratation canonique, extraction core et decode replay. Trois transactions réelles ont chacune produit une annotation et un second replay idempotent `skipped`.
|
|
||||||
|
|
||||||
La clôture utilisateur confirme : `kb_program_ids` 5 tests, `kb_decoder_spl_memo` 9, `kb_materializer_transaction_annotations` 7, `kb_executor_spl_memo` 15, `kb_execution_api` 22, `kb_execution_safety` 15, `kb_execution_solana` 12, `kb_pipeline` 61, `kb_rpc` 113, `kb_app_demo` 96 et `kb_store_pg` 46 avec PostgreSQL réel. Le test opt-in Devnet avec envoi est réussi et `cargo clippy --all-targets` est propre. La suite active devient `0.4.4 — SPL Token` selon `prompts/023_v0_4_4_spl_token.md`; l’acquisition historique différée reste hors ROADMAP actif.
|
|
||||||
|
|
||||||
## 0.4.4 — SPL Token classique
|
|
||||||
|
|
||||||
Validation complète du programme SPL Token classique `Tokenkeg...`. `kb_decoder_spl_token`
|
|
||||||
reconnaît exactement les 28 tags publiés par `spl-token-interface 3.0.0`, conserve le wire borné,
|
|
||||||
les comptes ordonnés, outer/inner paths, autorités simples ou multisig, montants bruts, decimals,
|
|
||||||
transactions échouées non commitées et diagnostics sans inventer mint ni état final. `Batch`
|
|
||||||
conserve son parent et ses enfants déterministes sans accepter les batchs imbriqués. La matrice
|
|
||||||
`docs/SPL_TOKEN_MATRIX.json` relie interface, processor, builders, corpus et preuves cluster.
|
|
||||||
|
|
||||||
Les projections stables produisent des événements instructionnels `token_account`, `admin` et
|
|
||||||
`risk`, sans fee classique fictive, sans OHLC et sans snapshot final reconstruit. Le replay Mainnet
|
|
||||||
de 370 instructions a produit 371 sorties, huit refus correspondant exactement à huit transactions
|
|
||||||
échouées, puis un second replay idempotent sans nouvelle sortie. Le journal Tauri expose des filtres
|
|
||||||
bornés par signature, mint, compte, famille et opération, avec montants JSON sans perte.
|
|
||||||
|
|
||||||
`kb_executor_spl_token` expose 24 opérations typées courantes ou récentes et laisse les quatre
|
|
||||||
initialisations Rent obsolètes en decode-only. Le préflight stateful Localnet/Devnet valide layouts,
|
|
||||||
relations mint/comptes, soldes, native reserve, délégations, autorités, multisig et rent hors du
|
|
||||||
décodeur et de l'exécuteur. Le parcours Devnet `TransferChecked` a réussi simulation, envoi,
|
|
||||||
confirmation, hydratation, extraction, replay, matérialisation et second replay idempotent. Un
|
|
||||||
lifecycle contrôlé sans ATA a ensuite initialisé mint et comptes, minté, transféré, approuvé,
|
|
||||||
révoqué, brûlé puis fermé les comptes avec récupération sûre après interruption RPC.
|
|
||||||
|
|
||||||
Les tags récents `Batch` et `UnwrapLamports` ont été simulés avec succès sur le programme classique
|
|
||||||
Devnet, sans signature ni envoi, respectivement en 270 et 140 compute units. La clôture Tauri charge
|
|
||||||
77 routes de logs, réussit le préflight et la simulation `TransferChecked`, bloque l'envoi sans
|
|
||||||
confirmation, affiche la matérialisation commitée exacte et simule Memo v4 sans erreur runtime.
|
|
||||||
|
|
||||||
La régression finale communiquée confirme notamment : `kb_program_ids` 5 tests,
|
|
||||||
`kb_decoder_spl_token` 8, `kb_executor_spl_token` 15, `kb_decoder_spl_memo` 9,
|
|
||||||
`kb_materializer_transaction_annotations` 7, `kb_execution_api` 22, `kb_execution_safety` 15,
|
|
||||||
`kb_execution_solana` 12, `kb_pipeline` 81, `kb_rpc` 113, `kb_config` 41, `kb_app_demo` 102 et
|
|
||||||
`kb_store_pg` 46 avec PostgreSQL réel. `cargo clippy --all-targets` est propre. La suite active
|
|
||||||
devient `0.4.5 — SPL Associated Token Account` selon
|
|
||||||
`prompts/024_v0_4_5_spl_associated_token_account.md`.
|
|
||||||
|
|
||||||
## 0.4.5 — SPL Associated Token Account
|
|
||||||
|
|
||||||
Validation complète du programme SPL Associated Token Account
|
|
||||||
`ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL`. Le décodeur consomme
|
|
||||||
`spl-associated-token-account-interface 2.0.0`, reconnaît exactement `Create`,
|
|
||||||
`CreateIdempotent`, `RecoverNested` et la forme historique vide de `Create`, puis conserve comptes
|
|
||||||
ordonnés, flags, doublons, chemins outer/inner, transactions échouées et diagnostics bornés. Les
|
|
||||||
adresses observées sont comparées aux PDA canoniques dérivés depuis wallet, Token Program ID et
|
|
||||||
mint ; une incohérence reste décodable et n'est jamais corrigée silencieusement.
|
|
||||||
|
|
||||||
`kb_materializer_token_accounts` possède exclusivement le lifecycle de l'adresse associée : créée,
|
|
||||||
créée ou réutilisée idempotemment, ou récupérée depuis une imbrication. `kb_materializer_risk`
|
|
||||||
possède le constat distinct d'anti-pattern nested récupéré, sans score arbitraire. Les CPI SPL Token
|
|
||||||
restent propriétaires des initialisations, transferts et fermetures, et les matérialiseurs lifecycle
|
|
||||||
général, admin et fees ne produisent aucun doublon. Les transactions non commitées ou invalides sont
|
|
||||||
refusées comme mutations.
|
|
||||||
|
|
||||||
`kb_executor_spl_associated_token_account` expose les trois variantes actuelles pour SPL Token
|
|
||||||
classique et Token-2022 avec les builders officiels, metas dans l'ordre exact, signataires uniques,
|
|
||||||
simulation obligatoire, dry-run par défaut et coûts rent/frais plafonnés. Le pipeline stateful
|
|
||||||
contrôle mints, owners, Program IDs, dérivations, comptes existants, rent, signataires et
|
|
||||||
postconditions avant et après l'exécution. La fenêtre Tauri Solana existante ajoute création ATA,
|
|
||||||
dérivation readonly et journal lifecycle borné ; `RecoverNested` reste volontairement hors UI.
|
|
||||||
|
|
||||||
Les scénarios Devnet contrôlés du 16 juillet 2026 ont validé la création et la réutilisation
|
|
||||||
idempotente d'ATA classiques et Token-2022, puis un `RecoverNested` classique transférant
|
|
||||||
1 000 000 000 unités brutes vers l'ATA wallet et fermant le nested ATA. Chaque envoi a suivi
|
|
||||||
simulation, confirmation, hydratation canonique, extraction, decode, matérialisation et second
|
|
||||||
replay idempotent. L'ATA Token-2022 observé mesure 170 octets et expose `ImmutableOwner`, sans que le
|
|
||||||
jalon ne commence le décodage général de ses extensions.
|
|
||||||
|
|
||||||
La clôture confirme 5 tests Program IDs, 8 tests décodeur Token classique, 15 tests exécuteur Token,
|
|
||||||
9 tests Memo, 7 tests annotations, 9 tests matérialiseur token accounts, 6 tests risk, 17 tests
|
|
||||||
lifecycle, 9 tests admin, 3 tests fees, 10 tests décodeur ATA, 10 tests exécuteur ATA, 22 tests API
|
|
||||||
d'exécution, 15 tests safety, 12 tests transaction Solana, 90 tests pipeline, 113 tests RPC, 41 tests
|
|
||||||
configuration, 111 tests démo et 46 tests PostgreSQL réels. `cargo clippy --all-targets` est propre
|
|
||||||
et `cargo tauri dev -c kb_app_demo/tauri.conf.json` a démarré Vite, Tauri et PostgreSQL. La suite
|
|
||||||
active devient `0.4.6 — Token-2022, extensions et registre ElGamal` selon
|
|
||||||
`prompts/025_v0_4_6_spl_token_2022.md`.
|
|
||||||
|
|
||||||
## 0.4.6 — Token-2022, extensions et registre ElGamal
|
|
||||||
|
|
||||||
Validation du jalon Token-2022 et ElGamal Registry avec frontières techniques séparées. Token-2022 couvre les instructions de base, les familles d’extensions identifiables, les états Mint/Account/Multisig et TLV, les metadata/group incorporés, les parcours confidentiels, les matérialisations propriétaires et les exécuteurs simulation-first avec préflights stateful et preuves inline/context-state. Huit opérations publiques Token-2022 ont été confirmées sur Devnet, hydratées, extraites, décodées, matérialisées et rejouées idempotemment. Le corpus Mainnet contient 55 instructions Token-2022 décodées sans échec.
|
|
||||||
Le registre ElGamal dispose de son décodeur, de sa matrice, de son parser d’état de 64 octets, de sa matérialisation administrative, de ses builders `CreateRegistry`/`UpdateRegistry`, de son PDA, de ses préflights et de son orchestration de preuves. La validation réseau publique reste indisponible sur Devnet/Mainnet au 20 juillet 2026 ; la validation synthétique/offline est conservée sans inventer de preuve cluster.
|
|
||||||
La validation Mainnet a corrigé le wire `Write` du loader immuable : longueur `u32` et données à l’offset 12, supprimant 68 diagnostics `loader_vector_length_mismatch`. Les 76 rejets restants sont tous issus de transactions Solana échouées et restent explicitement fail-closed ; quatre tags Loader v4 inconnus sont classés `Unsupported`. Un timeout ponctuel du pool PostgreSQL a été réparé par replay ciblé.
|
|
||||||
Le replay de `kb_app_demo` ajoute `incomplete_signatures`, qui sélectionne seulement les signatures contenant une instruction `pending`, `failed`, `replay_requested` ou `unsupported`, limite d’abord les signatures puis étend leurs instructions compatibles sans force replay global. Deux campagnes PostgreSQL réelles ont produit le même résultat : 81 entrées, 1 décodée, 4 unsupported, 76 failed, aucun unmatched et aucun doublon decode/mat. Validation finale : `kb_store_core` 41/41, `kb_store_pg` 46/46 avec PostgreSQL réel, `kb_pipeline` 124/124, `kb_app_demo` 118/118 et `cargo clippy --all-targets` propre. La suite active devient `0.4.7 — Metaplex Token Metadata` selon `prompts/026_v0_4_7_metaplex_token_metadata.md`. Anchor n’étant pas requis par les programmes SPL de `0.4.x`, son infrastructure commune est planifiée en `0.4.18`, immédiatement avant Meteora.
|
|
||||||
|
|
||||||
@@ -1,293 +0,0 @@
|
|||||||
<!-- file: README.md -->
|
|
||||||
<!-- version: 81 -->
|
|
||||||
|
|
||||||
# Khadhroony Bot2
|
|
||||||
|
|
||||||
Khadhroony Bot2 est un workspace Rust modulaire pour observer, décoder, matérialiser, exécuter et analyser des transactions Solana.
|
|
||||||
|
|
||||||
Le projet poursuit deux objectifs complémentaires. À court terme, il doit fournir un trading assisté contrôlable depuis des démos live Tauri. À long terme, il doit devenir une bibliothèque d'indexation et d'analyse Solana capable de classifier un grand nombre de programmes et de surfaces.
|
|
||||||
|
|
||||||
Le socle technique doit permettre de :
|
|
||||||
|
|
||||||
- ingérer des transactions Solana depuis RPC HTTP, WebSocket ou futures sources spécialisées ;
|
|
||||||
- normaliser chaque source vers une transaction canonique source-indépendante ;
|
|
||||||
- conserver la transaction canonique comme source d’audit et de replay ;
|
|
||||||
- conserver séparément les observations légères de provenance et de timing ;
|
|
||||||
- extraire les instructions, inner instructions, logs, comptes résolus et deltas de balances ;
|
|
||||||
- détecter les programmes impliqués dans chaque transaction ;
|
|
||||||
- décoder les programmes Solana de base, les programmes SPL, les surfaces DEX, les orderbooks, les routers et les protocoles annexes ;
|
|
||||||
- matérialiser les événements décodés en tables métier exploitables ;
|
|
||||||
- rejouer uniquement les modules nécessaires grâce à un ledger de traitement par module et version ;
|
|
||||||
- alimenter des agrégations, diagnostics, signaux de risque et futures règles de stratégie ;
|
|
||||||
- construire des plans d'exécution séparés des décodeurs ;
|
|
||||||
- tester les fonctionnalités live via `kb_app_demo` avant automatisation.
|
|
||||||
|
|
||||||
## Architecture générale
|
|
||||||
|
|
||||||
Le workspace suit une chaîne de traitement en couches :
|
|
||||||
|
|
||||||
```text
|
|
||||||
canonical transaction -> source observations -> Solana extraction -> decoding -> materialization -> aggregation -> strategy
|
|
||||||
```
|
|
||||||
|
|
||||||
Chaque couche doit être indépendante autant que possible. Les décodeurs ne dépendent pas du stockage, du RPC, de Tauri, du wallet ou des matérialisateurs. Les matérialisateurs travaillent sur les événements décodés et produisent des événements métier normalisés.
|
|
||||||
|
|
||||||
## Rôle des dossiers principaux
|
|
||||||
|
|
||||||
- `kb_core` contient les primitives partagées minimales.
|
|
||||||
- `kb_model` contient les types communs du modèle interne.
|
|
||||||
- `kb_config` définit le contrat JSON multi-profils, le schéma runtime, les validations typées et les exports TS-rs destinés aux applications Tauri.
|
|
||||||
- `kb_rpc` contient les protocoles et clients RPC Solana HTTP, WebSocket et futurs flux Helius/Yellowstone.
|
|
||||||
- `kb_execution_solana` assemble les plans communs en transactions Solana, lie la simulation au message exact et résout les signataires via l’interface Solana `Signer`; `kb_wallet` fournit actuellement le backend temporaire.
|
|
||||||
- Le projet différé d’acquisition historique gratuite est décrit dans `docs/HISTORICAL_DATA_ACQUISITION_PLAN.md`. Il reste hors du ROADMAP actif tant que les décodeurs, matérialisateurs et exécuteurs prioritaires ne sont pas suffisamment avancés.
|
|
||||||
- `kb_store_core` définit les traits de stockage.
|
|
||||||
- `kb_store_pg` fournit le backend PostgreSQL cible.
|
|
||||||
- `kb_store_sqlite` reste limité aux tests et imports locaux.
|
|
||||||
- `kb_decoder_api` définit le contrat des décodeurs.
|
|
||||||
- `kb_materializer_api` définit le contrat des matérialisateurs.
|
|
||||||
- `kb_materializer_*` contient les projections métier par famille : trades, liquidité, NFT, oracle, lending, routing, compliance audit, etc.
|
|
||||||
- `kb_pipeline` orchestre backfill, extraction canonique vers core, décodage, matérialisation, agrégation et validation.
|
|
||||||
- `kb_app_demo` sert de démonstrateur Tauri, sans logique métier lourde. Il charge le profil actif, initialise `kb_logging`, rend le README en HTML et expose une fenêtre dédiée à la configuration.
|
|
||||||
- Chaque crate opérationnelle doit émettre ses propres événements `tracing` avec une cible canonique égale à son nom Cargo ; `kb_app_demo` reste limité aux frontières UI/Tauri et aux résumés.
|
|
||||||
- Chaque profil écrit des fichiers globaux `debug.log`, `info.log`, `error.jsonl` et `app.log`, ainsi que `debug.log`, `info.log` et `error.jsonl` dans un répertoire par crate utilisant `tracing`.
|
|
||||||
- Les interfaces officielles Solana/SPL étroites sont privilégiées ; `wincode` puis Borsh sont préférés, et un parser local borné reste autorisé lorsque l’interface officielle n’expose que `bincode`.
|
|
||||||
|
|
||||||
|
|
||||||
## État `0.4.1` validé
|
|
||||||
|
|
||||||
`0.4.1` clôt le décodage et les matérialisations instructionnelles stables des programmes Solana natifs, historiques, loaders, précompiles et surfaces ZK du périmètre core.
|
|
||||||
|
|
||||||
`kb_decoder_solana_core` couvre maintenant 18 surfaces exécutables natives : System, Vote, Stake, Config, Compute Budget, Address Lookup Table, Feature, ZK ElGamal Proof, l’ancien ZK Token Proof historique/no-op, Native Loader, BPF Loader v1/v2/Upgradeable/v4, Ed25519, secp256k1, secp256r1 et Slashing. `StakeConfig11111111111111111111111111111111` est classé comme compte historique non exécutable, sans dispatch ni plan d’exécution.
|
|
||||||
|
|
||||||
Les matérialisations natives actives sont réparties par famille :
|
|
||||||
|
|
||||||
- `kb_materializer_lifecycle` : Address Lookup Table, lifecycle loaders, Feature revoke, durable nonce, comptes System create/allocate, contextes ZK ElGamal et rapports Slashing ;
|
|
||||||
- `kb_materializer_admin` : assignations System, écritures Config opaques, changements d’autorité Loader ;
|
|
||||||
- `kb_materializer_compliance_audit` : écritures/copies de bytecode Loader et profil transactionnel Compute Budget ;
|
|
||||||
- `kb_materializer_staking` : projections instructionnelles Stake/Vote commitées, sans prétendre reconstruire les snapshots finaux.
|
|
||||||
|
|
||||||
Les précompiles de signature, les preuves ZK sans compte de contexte et l’ancien ZK Token Proof restent en decode/audit, sans duplication dans `kb_sol_mat_events` tant qu’aucun consommateur dédié ne l’exige. Les transactions échouées restent décodées comme intentions ou échecs, mais les matérialiseurs mutables appliquent `SuccessfulCommittedOnly`.
|
|
||||||
|
|
||||||
Les validations finales de `0.4.1` couvrent les tests unitaires, PostgreSQL réel, Clippy et des replays mainnet ciblés : System, Config, Stake, Vote, Compute Budget, ALT, ZK ElGamal et Slashing synthétique. Les replays terminent sans `unmatched`, `failedInputs` ou `unsupported`; les archives de logs fournies ont des `error.jsonl` vides.
|
|
||||||
|
|
||||||
## Couche d'exécution
|
|
||||||
|
|
||||||
Le workspace développe une couche d'exécution séparée du décodage. Les crates `kb_executor_*` sont des bibliothèques universelles : elles construisent des plans pour les applications de trading, les CLI, les workers, les outils d'administration et de futurs exécutables indépendants.
|
|
||||||
|
|
||||||
Les opérations dangereuses ne sont pas supprimées des bibliothèques. Elles doivent être encodées, testées et protégées par des politiques renforcées, tandis que `kb_app_demo` peut volontairement ne pas les exposer. Les exécuteurs ne dépendent ni du wallet, ni du RPC, ni des décodeurs ; l'orchestration assemble ensuite plan, sécurité, simulation, signature, envoi et validation post-exécution.
|
|
||||||
|
|
||||||
## Démos live
|
|
||||||
|
|
||||||
`kb_app_demo` reste le shell Tauri unique pour valider les capacités du workspace : configuration, logs, DB, RPC, wallet, listeners, décodage, matérialisation, exécution et validation post-transaction.
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
- `RUST_RULES.md` contient les règles Rust générales réutilisables ; `RULES.md` contient les règles spécifiques et normatives du workspace.
|
|
||||||
- `ROADMAP.md` contient les étapes futures et changements prévus.
|
|
||||||
- `CHANGELOG.md` ne reçoit une entrée qu'après validation d'une version.
|
|
||||||
- `docs/` contient les notes d'architecture et de conception, notamment `TRACING_CONTRACT.md`, `SOLANA_INTERFACE_DEPENDENCIES.md`, `NATIVE_SOLANA_CLOSURE_AUDIT.md`, `NATIVE_SOLANA_MATERIALIZATION_AUDIT.md` et `DEVNET_EXECUTION.md`.
|
|
||||||
- `validation_sql/` contient les contrôles SQL de validation.
|
|
||||||
|
|
||||||
## Jalon validé `0.4.2`
|
|
||||||
|
|
||||||
`0.4.2` valide l’infrastructure d’exécution et `kb_executor_solana_core`. L’exécuteur expose **109 opérations déterministes** : dix-sept System, quatre Compute Budget, cinq Address Lookup Table, six formes de précompile, deux Config, deux Feature, deux Slashing, trois ZK ElGamal, vingt-quatre Stake, vingt-quatre Vote, onze Loader v3 et neuf Loader v4. La surface Vote couvre les vingt variantes wire actuelles de `solana-vote-interface 6.0.3` ainsi que quatre plans composés de création legacy/V2, avec ou sans seed. Loader v3 consomme `solana-loader-v3-interface 8.x` et son schéma `wincode`; Loader v4 reproduit explicitement son wire officiel sans activer les helpers conditionnés par `bincode`. BPF Loader v1/v2 restent historiques `decode-only`, Native Loader ne possède pas de builder client et l’ancien ZK Token Proof reste historique. Les opérations nécessitant un état courant restent protégées par un préflight séparé et ne sont pas activées sur Mainnet par ce jalon.
|
|
||||||
|
|
||||||
`kb_pipeline` fournit le préflight stateful Localnet/Devnet pour ALT, Config, Feature, Slashing et les contextes ZK ElGamal. Le rapport `Ready`/`Blocked`/`NotRequired` expose les contrôles et faits mesurés avant simulation. `docs/NATIVE_SOLANA_EXECUTION_MATRIX.json` inventorie les dix-huit surfaces et les 109 opérations appelables, avec égalité imposée par un test Rust. La matrice décodeur couvre les mêmes dix-huit surfaces et 121 déclarations de couverture.
|
|
||||||
|
|
||||||
`kb_rpc` possède des contrats propres et configurables pour les 52 méthodes HTTP standard et les neuf paires WebSocket standard. Les options restent composables champ par champ et aucun DTO Agave n’est exposé par l’API publique. La session WebSocket persistante gère multiplexage, unsubscribe, timeout, reconnexion et réabonnement. `blockSubscribe`, `slotsUpdatesSubscribe` et `voteSubscribe` sont activables par endpoint ; lorsqu’un nœud les rejette comme indisponibles, la capacité concernée est désactivée automatiquement pour la session et les appels suivants sont refusés localement.
|
|
||||||
|
|
||||||
`kb_wallet` fournit un wallet temporaire en mémoire ou persistant sous `wallets/temporary/`, avec fichiers non écrasés, permissions privées et secrets confinés côté Rust. `kb_execution_solana` assemble les transactions, lie la simulation au hash exact du message et signe seulement après autorisation de `kb_execution_safety`. `kb_pipeline` orchestre le parcours backend Devnet complet : contrôle du destinataire et du minimum rent-exempt, financement plafonné, System transfer, simulation exacte, signature, envoi, confirmation, hydratation canonique, extraction core et decode replay ciblé. Ce parcours a été validé réellement sur Devnet avec un transfert de 1 000 000 lamports et PostgreSQL réel.
|
|
||||||
|
|
||||||
La frontière Tauri/TS-rs n’émet plus de `bigint` dans les payloads JSON actifs. Les identifiants WebSocket sont contrôlés contre `Number.isSafeInteger`, et les limites du navigateur SQL sont validées côté frontend avant l’appel backend. `cargo tauri dev` avec Vite constitue la validation frontend retenue ; aucun `npm run build` séparé n’est exigé pour cette clôture.
|
|
||||||
|
|
||||||
## Jalon validé `0.4.3`
|
|
||||||
|
|
||||||
Le prompt `prompts/022_v0_4_3_spl_memo.md` reste l’historique de travail du jalon. Le décodeur contextualisé distingue v1, v3 et v4 avec payload UTF‑8 ou tentative invalide, comptes ordonnés, signataires, outer/inner, hash et intentions non commitées. La projection dédiée `kb_materializer_transaction_annotations` transforme uniquement les Memo réussis et commités en annotations consultables et idempotentes ; les faits d’audit détaillés restent dans le decode. `demo_decode_replay` expose ces sorties comme un journal borné filtrable par signature, avec slot, instruction path, génération, texte, hash et signataires vérifiés.
|
|
||||||
|
|
||||||
`kb_executor_spl_memo` expose maintenant un intent typé `AddMemo` et appelle le builder officiel `spl-memo-interface 2.1.0` avec l’ID explicite v1/v3/v4. Le wire reste le texte UTF‑8 brut et chaque signer est readonly, ordonné et visible avant signature. La bibliothèque construit les trois générations sur tout cluster ; la disponibilité effective du programme est vérifiée par la simulation obligatoire, et Mainnet reste régi par les garde-fous communs plutôt que désactivé dans l’exécuteur. La démo opérateur reste volontairement limitée à Memo v4 Devnet et réutilise la fenêtre Solana existante. Elle montre la simulation, l’envoi explicitement confirmé, l’hydratation, l’extraction, le replay, l’annotation et l’idempotence avec des DTO Tauri JSON sans `bigint` actif.
|
|
||||||
|
|
||||||
Le parcours a été validé le 15 juillet 2026 avec une simulation seule puis trois transactions v4 Devnet confirmées. Chaque signature a produit une insertion canonique, une extraction core, un événement Memo, une annotation `transaction_annotation` et un second replay `skipped` sans nouvelle sortie. Le corpus Mainnet réel couvre séparément v1, v3 et v4 ; aucun envoi historique v1/v3 sur Devnet n’est revendiqué ni requis.
|
|
||||||
|
|
||||||
La matrice `docs/SPL_MEMO_MATRIX.json` conserve les différences historiques, le corpus Mainnet réel, les preuves Devnet v4 et les limitations explicitement non revendiquées pour v1/v3. Le worker d’acquisition historique reste un projet différé indépendant, sans numéro de version attribué.
|
|
||||||
|
|
||||||
La validation finale confirme 5 tests `kb_program_ids`, 9 tests décodeur Memo, 7 tests matérialiseur d’annotations, 15 tests exécuteur Memo, 22 tests API d’exécution, 15 tests safety, 12 tests Solana, 61 tests pipeline, 113 tests RPC, 96 tests démo et 46 tests PostgreSQL réels. Le test opt-in Devnet avec envoi et `cargo clippy --all-targets` sont propres. La version active devient `0.4.4 — SPL Token` selon `prompts/023_v0_4_4_spl_token.md`.
|
|
||||||
|
|
||||||
## Jalon validé `0.4.4`
|
|
||||||
|
|
||||||
Les premières tranches SPL Token établissent la matrice machine-readable des 28 tags publiés par
|
|
||||||
`spl-token-interface 3.0.0` et remplacent le scaffold du décodeur classique. Le wire local borné
|
|
||||||
conserve montants bruts, decimals explicites, autorités, comptes ordonnés, chemins outer/inner,
|
|
||||||
transactions échouées non commitées, suffixes et diagnostics. `Batch` produit un parent d'audit et
|
|
||||||
des enfants à identités dérivées stables sans accepter de batch imbriqué.
|
|
||||||
|
|
||||||
Les matérialiseurs actifs produisent un journal instructionnel `token_account`, des faits admin et
|
|
||||||
des constats de risque sans score ; aucune fee classique n'est inventée. Le replay Mainnet validé de
|
|
||||||
370 instructions a produit 371 sorties, huit refus expliqués par huit transactions échouées et un
|
|
||||||
second replay idempotent sans nouvelle sélection.
|
|
||||||
|
|
||||||
`kb_executor_spl_token` expose 24 opérations typées courantes ou récentes avec montants JSON en
|
|
||||||
chaînes, autorités simples/multisig et builders officiels. Quatre initialisations Rent obsolètes
|
|
||||||
restent decode-only. `UnwrapLamports` et `Batch` sont constructibles selon l'interface publiée ; leur
|
|
||||||
déploiement sur le programme classique Devnet a été observé le 16 juillet 2026 par deux simulations
|
|
||||||
réussies sans signature ni envoi. Localnet, Testnet et Mainnet restent non testés pour ces deux tags.
|
|
||||||
|
|
||||||
`0.4.4-pre.005` ajoute le préflight stateful Localnet/Devnet dans `kb_pipeline`. Les lectures RPC
|
|
||||||
restent hors du décodeur et de l’exécuteur ; elles valident les layouts Mint/Account/Multisig,
|
|
||||||
l’état, les relations de mint, les soldes, les réserves wrapped SOL, les délégations, les autorités,
|
|
||||||
les seuils multisig et le rent avant simulation. Les tests standards sont offline et un test Devnet
|
|
||||||
read-only reste opt-in. La démo Token réutilise la fenêtre d’exécution Solana existante : son panneau
|
|
||||||
`TransferChecked` expose préflight, simulation, confirmation et validation post-exécution, tandis
|
|
||||||
qu’un journal matérialisé borné accepte des filtres typés par signature, mint, compte, famille et
|
|
||||||
opération sans créer une WebView par opération.
|
|
||||||
|
|
||||||
Le correctif fonctionnel de `pre.005` ajoute l’orchestration Devnet générique : simulation autonome
|
|
||||||
après préflight, puis envoi explicitement confirmé lorsque le wallet du profil résout tous les
|
|
||||||
signataires. Une transaction envoyée est confirmée, hydratée, extraite, décodée et matérialisée,
|
|
||||||
avant un second replay idempotent. Cette couche ne restreint pas les builders universels aux seuls
|
|
||||||
clusters ou signataires disponibles dans la démo.
|
|
||||||
|
|
||||||
Le parcours `TransferChecked` a été validé réellement sur Devnet le 15 juillet 2026 avec deux
|
|
||||||
comptes Token auxiliaires du même mint et un wallet isolé correspondant exactement à l’autorité.
|
|
||||||
Le test opt-in impose désormais la présence de la soumission et de la confirmation, l’absence
|
|
||||||
d’échec ou de refus au premier replay, au moins une matérialisation Token et un second replay sans
|
|
||||||
nouvelle sortie ; il imprime aussi la signature afin qu’elle puisse rejoindre le corpus audité.
|
|
||||||
|
|
||||||
`0.4.4-pre.006` ajoute un lifecycle destructif explicitement autorisé pour trois comptes classiques
|
|
||||||
sans ATA. Son correctif crée d'abord les comptes bruts via trois instructions System officielles,
|
|
||||||
avec keypairs éphémères, rent et tailles 82/165/165 vérifiés, puis onze transactions initialisent le mint et deux comptes Token, mintent et
|
|
||||||
transfèrent un montant contrôlé, créent puis révoquent une délégation, brûlent exactement les deux
|
|
||||||
soldes et ferment les comptes Token. Chaque étape est simulée, confirmée, hydratée, décodée,
|
|
||||||
matérialisée et rejouée une seconde fois avant que l'étape suivante ne soit admise.
|
|
||||||
|
|
||||||
Le correctif de reprise du lifecycle traite explicitement les confirmations RPC interrompues : une
|
|
||||||
signature prédécesseur confirmée est hydratée, extraite, décodée, rapprochée de l'opération attendue
|
|
||||||
et rejouée idempotemment avant de reprendre à l'index demandé. Un délai borné sépare ensuite les
|
|
||||||
étapes afin de réduire la pression sur les endpoints Devnet publics, sans masquer leurs erreurs.
|
|
||||||
|
|
||||||
Le lifecycle Devnet réel a été validé le 15 juillet 2026 après une interruption du RPC public : la
|
|
||||||
reprise a récupéré l'initialisation déjà confirmée, puis achevé mint, transfer, approve/revoke, deux
|
|
||||||
burn et deux close. Chaque étape récupérée ou envoyée a produit exactement une matérialisation et un
|
|
||||||
second replay idempotent. La fenêtre opérateur `pre.007` permet désormais de rejouer le parcours
|
|
||||||
représentatif `TransferChecked` et de consulter ces faits `token_account`, `admin` et `risk` comme
|
|
||||||
événements chronologiques, sans inventer un état final de compte.
|
|
||||||
|
|
||||||
L'audit `pre.008` reporte dans `docs/SPL_TOKEN_MATRIX.json` les preuves par instruction. Le corpus
|
|
||||||
Mainnet réel couvre `Transfer`, `Approve`, `CloseAccount`, `TransferChecked`, `BurnChecked` et
|
|
||||||
`SyncNative`; ses trois initialisations restent volontairement référencées sous leur nom matérialisé
|
|
||||||
normalisé sans inventer une variante wire. Le lifecycle Devnet prouve `InitializeAccount3`,
|
|
||||||
`MintToChecked`, `TransferChecked`, `ApproveChecked`, `Revoke`, `BurnChecked` et `CloseAccount`.
|
|
||||||
Localnet n'a pas été exécuté, et la publication p-token des tags `45`/`255` n'est pas assimilée à
|
|
||||||
leur déploiement sur un cluster public.
|
|
||||||
|
|
||||||
La validation Tauri de `pre.007` a démarré Vite et l'application, réussi le préflight et la
|
|
||||||
simulation `TransferChecked`, puis refusé correctement l'envoi sans confirmation opérateur. Avec
|
|
||||||
confirmation, un second refus a identifié que le wallet du profil et l'autorité Token étaient deux
|
|
||||||
clés distinctes. La démo ne tente jamais de signer à la place d'une autorité externe ; pour envoyer,
|
|
||||||
les comptes Token doivent appartenir au wallet persistant sélectionné, comme dans le scénario
|
|
||||||
backend Devnet déjà confirmé et matérialisé.
|
|
||||||
|
|
||||||
La clôture du 16 juillet 2026 confirme les régressions ciblées, PostgreSQL réel, Clippy et Tauri.
|
|
||||||
Les validations finales couvrent notamment 5 tests Program IDs, 8 tests décodeur Token, 15 tests
|
|
||||||
exécuteur Token, 9 tests décodeur Memo, 7 tests annotations, 22 tests API d'exécution, 15 tests
|
|
||||||
safety, 12 tests transaction Solana, 81 tests pipeline, 113 tests RPC, 41 tests configuration,
|
|
||||||
102 tests démo et 46 tests PostgreSQL réels. Tauri charge 77 routes de logs, simule
|
|
||||||
`TransferChecked`, bloque l'envoi non confirmé, restitue sa matérialisation commitée exacte et
|
|
||||||
simule Memo v4 sans erreur runtime.
|
|
||||||
|
|
||||||
## Jalon validé `0.4.5`
|
|
||||||
|
|
||||||
`0.4.5` clôt la surface SPL Associated Token Account avec
|
|
||||||
`spl-associated-token-account-interface 2.0.0`. Le décodeur reconnaît exactement `Create`,
|
|
||||||
`CreateIdempotent`, `RecoverNested` et la forme historique vide de `Create`; il conserve comptes
|
|
||||||
ordonnés, flags, doublons, outer/inner paths, transactions échouées non commitées et diagnostics
|
|
||||||
bornés. Les PDA sont dérivés et validés explicitement avec les seeds
|
|
||||||
`[wallet, Token Program ID, mint]`, ce qui distingue les ATA classiques des ATA Token-2022 sans
|
|
||||||
prétendre décoder les extensions de ce dernier.
|
|
||||||
|
|
||||||
Le lifecycle ATA est possédé par `kb_materializer_token_accounts` : création normale, création ou
|
|
||||||
réutilisation idempotente non distinguable depuis le parent seul, et récupération nested.
|
|
||||||
`kb_materializer_risk` possède séparément le constat factuel d'anti-pattern nested récupéré. Les
|
|
||||||
matérialiseurs lifecycle général, admin et fees déclarent explicitement leur absence de projection,
|
|
||||||
et les CPI SPL Token conservent seules leurs initialisations, transferts et fermetures. Les
|
|
||||||
transactions échouées ou structurellement invalides ne produisent aucune mutation.
|
|
||||||
|
|
||||||
`kb_executor_spl_associated_token_account` construit les trois variantes actuelles avec les
|
|
||||||
builders officiels, pour SPL Token classique ou Token-2022. Simulation et dry-run sont obligatoires
|
|
||||||
par défaut. Le préflight Localnet/Devnet contrôle cluster, mints, Program IDs, dérivations, comptes
|
|
||||||
existants, signataires, rent et plafonds ; la post-validation vérifie création/réutilisation ou les
|
|
||||||
conditions de fermeture/transfert de `RecoverNested`.
|
|
||||||
|
|
||||||
Les preuves Devnet du 16 juillet 2026 couvrent deux parcours complets `CreateIdempotent` classiques,
|
|
||||||
la création puis la réutilisation d'un ATA Token-2022 avec `ImmutableOwner`, et un
|
|
||||||
`RecoverNested` classique transférant 1 000 000 000 unités brutes avant fermeture du nested ATA.
|
|
||||||
Chaque soumission a été simulée, confirmée, hydratée, extraite, décodée et matérialisée, puis rejouée
|
|
||||||
sans doublon. La fenêtre Tauri unique expose création ATA et journal lifecycle borné ;
|
|
||||||
`RecoverNested` reste couvert hors UI par un test opt-in contrôlé.
|
|
||||||
|
|
||||||
La validation finale confirme les régressions Token/Memo, 10 tests décodeur ATA, 10 tests exécuteur
|
|
||||||
ATA, 90 tests pipeline, 113 tests RPC, 41 tests configuration, 111 tests démo, 46 tests PostgreSQL
|
|
||||||
réels et `cargo clippy --all-targets` propre. Les versions Rust, npm et Tauri sont synchronisées en
|
|
||||||
`0.4.5`.
|
|
||||||
|
|
||||||
## Jalon validé `0.4.6`
|
|
||||||
|
|
||||||
`0.4.6` clôt Token-2022 et le registre ElGamal comme surfaces séparées. Token-2022 couvre les instructions de base, les extensions identifiables, les états Mint/Account/Multisig et TLV, les matérialisations propriétaires et les exécuteurs simulation-first. Le registre ElGamal conserve son propre Program ID, sa matrice, son état de 64 octets, son PDA et ses opérations administratives ; il n’est pas fusionné avec Token-2022 ni avec le programme natif ZK ElGamal Proof.
|
|
||||||
|
|
||||||
La validation publique Token-2022 comprend huit opérations Devnet confirmées et 55 instructions Mainnet décodées sans échec. La validation réseau ElGamal Registry reste indisponible sur les clusters publics au 20 juillet 2026, mais ses builders, parsers, préflights, preuves et scénarios stateful sont validés synthétiquement/offline. Le bilan détaillé est publié dans `docs/V0_4_6_VALIDATION.md`.
|
|
||||||
|
|
||||||
Le replay contextualisé dispose désormais du mode `incomplete_signatures`. Il sélectionne uniquement les signatures contenant au moins une instruction `pending`, `failed`, `replay_requested` ou `unsupported`, applique la limite aux signatures avant expansion et réévalue leurs instructions compatibles sans activer le force replay global. Deux campagnes PostgreSQL réelles ont sélectionné 81 entrées chacune : 1 décodée, 4 unsupported et 76 rejets fail-closed appartenant tous à des transactions Solana échouées.
|
|
||||||
|
|
||||||
La régression finale confirme `kb_store_core` 41/41, `kb_store_pg` 46/46 avec PostgreSQL réel, `kb_pipeline` 124/124, `kb_app_demo` 118/118 et `cargo clippy --all-targets` propre.
|
|
||||||
|
|
||||||
## Jalon actif `0.4.7`
|
|
||||||
|
|
||||||
La suite active est Metaplex Token Metadata selon `prompts/026_v0_4_7_metaplex_token_metadata.md`. La préversion `0.4.7-pre.001` ouvre l’audit avec les crates `kb_decoder_metadata_metaplex_token_metadata` et `kb_executor_metadata_metaplex_token_metadata`, ainsi que `docs/METAPLEX_TOKEN_METADATA_MATRIX.json`, sans activation runtime tant que le wire complet n’est pas prouvé. L’exécuteur existe comme frontière audit-only parce que le SDK officiel fournit des builders, mais il n’expose encore aucune construction de transaction. Ce programme indépendant complète les metadata externes des mints SPL Token classique et Token-2022 sans être absorbé par leurs décodeurs. La priorité porte sur la frontière exacte du Program ID, les PDA et layouts versionnés, les NFT/collections/programmable assets, la provenance des metadata et le replay PostgreSQL idempotent.
|
|
||||||
|
|
||||||
Anchor n’est pas requis par les programmes SPL planifiés dans `0.4.x`. Son infrastructure commune est reportée à `0.4.18`, immédiatement avant Meteora, afin d’être conçue à partir des besoins réels des protocoles Anchor sans retarder Metaplex et les autres surfaces Core/SPL.
|
|
||||||
|
|
||||||
## Backend de données
|
|
||||||
|
|
||||||
PostgreSQL est le backend principal prévu. SQLite reste présent uniquement pour les tests, les imports ponctuels ou les petits corpus locaux.
|
|
||||||
|
|
||||||
Les tables Solana PostgreSQL utilisent le schéma courant du profil, généralement `public`. Le projet ne crée pas de schémas applicatifs explicites comme `raw`, `core`, `obs`, `decode`, `mat`, `catalog`, `agg`, `ops` ou `wallet`. La séparation logique se fait dans le nom physique de table au format `kb_sol_<domain>_<name>`, par exemple `kb_sol_raw_transactions`.
|
|
||||||
|
|
||||||
## Replay des signatures incomplètes
|
|
||||||
|
|
||||||
La fenêtre de replay contextualisé de `kb_app_demo` expose un mode `signatures_incomplete`. Il sélectionne uniquement les signatures contenant au moins une instruction `pending`, `failed`, `replay_requested` ou un résultat `unsupported`, puis réévalue les instructions compatibles de ces signatures sans activer le force replay global. La limite porte sur le nombre de signatures incomplètes avant expansion. La matérialisation reste optionnelle et idempotente.
|
|
||||||
|
|
||||||
Ce mode est destiné aux backfills croissants : une correction de décodeur peut reprendre seulement les signatures incomplètes au lieu de rejouer toutes les signatures déjà réussies.
|
|
||||||
|
|
||||||
## Livraison par delta
|
|
||||||
|
|
||||||
Après le squelette initial, les modifications doivent être livrées sous forme de zip delta contenant uniquement les fichiers ajoutés ou modifiés. Un delta multi-module ou racine utilise `khadhroony-bot2_vX.Y.Z-pre.abc-delta.zip`. Un delta limité à un module Rust utilise `kb_modulename_vX.Y.Z-pre.abc-delta.zip`. Un correctif conserve le même numéro `pre.abc` et ajoute `-delta-fix-001.zip`, puis `-fix-002.zip`, au lieu d’incrémenter la préversion. Chaque archive contient un `delta.md` non versionné listant les fichiers ajoutés, modifiés, à supprimer manuellement, ainsi que les validations exécutées ou non exécutées.
|
|
||||||
|
|
||||||
## Surfaces réservées
|
|
||||||
|
|
||||||
Le workspace réserve dès le squelette les crates de décodage pour les DEX, launchpads, orderbooks, routers, perps et surfaces candidates recensés dans `idls/` et dans la documentation de conception. Ces crates restent des points d'ancrage tant que les discriminants, corpus et règles de matérialisation ne sont pas validés.
|
|
||||||
|
|
||||||
|
|
||||||
## Registres de programmes
|
|
||||||
|
|
||||||
Le workspace distingue deux registres :
|
|
||||||
|
|
||||||
- `registry/program_registry_seed.toml` pour les surfaces applicatives et protocolaires ;
|
|
||||||
- `registry/core_program_id_seed.toml` pour les programmes primitifs, loaders, sysvars et comptes natifs Solana/SPL.
|
|
||||||
|
|
||||||
Les comptes non exécutables observés pendant la recherche restent documentés dans `docs/ACCOUNT_ONLY_CANDIDATES.md`. Bags dispose maintenant aussi d'une note dédiée dans `docs/BAGS_FM.md` pour les programmes Fee Share V1/V2 confirmés.
|
|
||||||
|
|
||||||
## Classification des surfaces
|
|
||||||
|
|
||||||
La classification des IDL locales est suivie dans `docs/IDL_SURFACE_CLASSIFICATION.md`. Le registre machine principal reste `registry/program_registry_seed.toml`.
|
|
||||||
|
|
||||||
## Configuration, endpoints et listeners
|
|
||||||
|
|
||||||
Le workspace utilise `kb_config` pour charger plusieurs profils de configuration, avec un seul profil actif. Le fichier JSON est d'abord validé par `config/schema.config.json`, puis désérialisé et validé par les règles métier Rust.
|
|
||||||
|
|
||||||
Le pipeline normalise toutes les sources vers une transaction canonique commune. HTTP JSON-RPC est utilisé d’abord pour les backfills gratuits. Helius `transactionSubscribe` et Yellowstone gRPC seront ajoutés plus tard dans `kb_rpc`, après les décodeurs prioritaires, sans créer de crate provider séparée. La fenêtre `demo_backfill` permet de lancer des campagnes bornées par liste de signatures, programme, token ou pool. En direction « avant, plus anciennes », une ancre vide commence sur la page la plus récente ; la direction « après, plus récentes » exige toujours une signature d’ancrage.
|
|
||||||
|
|
||||||
Les listeners WebSocket doivent permettre la détection temps réel des créations de token, créations de pool, migrations, swaps, changements de liquidité et changements sur les tokens ou pools surveillés. Les exports TS-rs de `kb_config` servent uniquement à partager les types Rust/TypeScript avec les applications Tauri comme `kb_app_demo`, puis les futures applications wallet ou finales. Les payloads Tauri partagés, comme la page de configuration, doivent aussi être exportés par TS-rs depuis leur crate applicative.
|
|
||||||
|
|
||||||
### Metaplex Token Metadata `0.4.7-pre.016`
|
|
||||||
|
|
||||||
L’inventaire officiel complet des modules d’instruction a été réaudité avant le passage aux comptes on-chain. `FreezeDelegatedAccount` et `ThawDelegatedAccount` historiques sont désormais décodés avec leurs contrats exacts ; les autres surfaces encore absentes restent planifiées avant toute déclaration de couverture exhaustive.
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,231 +0,0 @@
|
|||||||
<!-- file: RULES.md -->
|
|
||||||
<!-- version: 16 -->
|
|
||||||
|
|
||||||
# Règles spécifiques à `khadhroony-bot2`
|
|
||||||
|
|
||||||
Ce fichier contient uniquement les règles propres au projet et au workspace `khadhroony-bot2`.
|
|
||||||
|
|
||||||
Les règles Rust générales et réutilisables dans tous les projets sont définies dans [`RUST_RULES.md`](RUST_RULES.md). Les deux fichiers sont normatifs et cumulatifs. En cas de conflit, la règle la plus stricte s'applique ; une règle spécifique au workspace ne peut jamais assouplir une règle générale sans exception explicitement documentée.
|
|
||||||
|
|
||||||
Toute livraison doit exécuter l'audit `python3 scripts/audit_rust_workspace_rules.py`. Tant que l'audit global n'est pas propre, les écarts existants doivent être résorbés par lots de correctifs avant toute nouvelle prérelease.
|
|
||||||
|
|
||||||
## Règles de nommage
|
|
||||||
|
|
||||||
- Tous les noms de fichiers et de répertoires doivent être écrits en anglais.
|
|
||||||
- Les noms de fichiers et de répertoires ne doivent contenir aucun accent, espace ou caractère spécial inutile.
|
|
||||||
- Les noms internes doivent utiliser le format `snake_case` lorsque c'est applicable.
|
|
||||||
- Les crates Rust utilisent le préfixe `kb_`.
|
|
||||||
- Les crates de décodeur utilisent le format `kb_decoder_<protocol>_<surface>`.
|
|
||||||
- Les crates de matérialisation utilisent le format `kb_materializer_<family>`.
|
|
||||||
- Le crate de journalisation s'appelle `kb_logging`.
|
|
||||||
|
|
||||||
## Règles Tauri et TypeScript
|
|
||||||
|
|
||||||
- Toute structure ou énumération Rust exposée au frontend TypeScript doit importer le trait `TS` avec `use ts_rs::TS;` puis dériver `TS`.
|
|
||||||
- Les types Rust exportés vers TypeScript doivent utiliser des noms stables et explicites.
|
|
||||||
- Les bindings générés doivent être produits dans un dossier dédié, généralement `../frontend/ts/bindings` ou `#[ts(export, export_to = "../frontend/ts/bindings/MyStruct.ts")]`.
|
|
||||||
- Les types purement internes au backend ne doivent pas être exportés vers TypeScript par défaut.
|
|
||||||
- Un payload de commande ou d’événement Tauri traverse une frontière JSON et ne doit jamais exiger un `bigint` JavaScript. Pour un entier Rust borné et représentable par l’UI, utiliser un override TS-rs `number`; si l’exactitude au-delà de `Number.MAX_SAFE_INTEGER` est nécessaire, sérialiser explicitement une chaîne décimale côté Rust et exporter `string`. Ne jamais construire un `BigInt` dans un objet passé à `invoke` ou `emit`.
|
|
||||||
- Corriger le type Rust/TS-rs source puis régénérer les bindings ; ne pas considérer une modification manuelle isolée d’un fichier généré comme un correctif durable.
|
|
||||||
|
|
||||||
## Règles d'architecture
|
|
||||||
|
|
||||||
- Les décodeurs ne dépendent pas de PostgreSQL, SQLite, RPC, Tauri, wallet, stratégie ou matérialisateurs.
|
|
||||||
- Les matérialisateurs ne dépendent pas du RPC, du wallet, de Tauri ou des décodeurs spécifiques.
|
|
||||||
- Pour chaque programme Solana, quelle que soit sa famille, un décodeur doit couvrir maximalement tout wire officiellement identifiable de sa surface, qu'il soit historique, courant, récent, expérimental ou publié avant son déploiement généralisé. Ces statuts doivent rester explicites et ne constituent pas un motif pour supprimer le décodage.
|
|
||||||
- Une observation lisible issue d'une transaction échouée peut conserver une intention non commitée ; elle ne doit jamais être présentée comme une mutation réussie.
|
|
||||||
- Pour chaque programme Solana, les matérialisateurs doivent projeter maximalement tous les faits métier stables et prouvés par le décodage, y compris les états historiques, obsolètes, dépréciés ou seulement rencontrables pendant un backfill. Le statut historique interdit l'exécution, mais ne constitue jamais à lui seul un motif de non-matérialisation.
|
|
||||||
- Toute projection historique doit conserver explicitement son lifecycle, sa version de layout, sa provenance, son slot ou ordre d'observation lorsqu'ils sont connus, et ne doit jamais écraser silencieusement un état actif plus récent.
|
|
||||||
- Une même réalité métier doit avoir une seule projection canonique. Les snapshots de comptes sont la source autoritative de l'état final lorsqu'ils sont disponibles ; les instructions et événements corrélés restent des observations de mutation et ne doivent pas produire un doublon concurrent du même état.
|
|
||||||
- Les matérialisateurs doivent refuser les transactions non commitées pour les mutations d'état, tout en pouvant conserver séparément une intention non commitée lorsque le modèle métier le prévoit explicitement.
|
|
||||||
- Toute absence volontaire de projection doit être documentée avec une justification technique précise. Un matérialisateur ne doit inventer ni état final, ni montant, ni autorité, ni frais, ni agrégation que l'observation ne prouve pas.
|
|
||||||
- Pour chaque programme Solana, les exécuteurs doivent couvrir maximalement les opérations officiellement appelables et les opérations expérimentales publiées lorsque leurs contrats exacts et garde-fous sont prouvés. Les opérations historiques, dépréciées ou obsolètes doivent rester décodables et matérialisables, mais ne doivent jamais être exposées à l'exécution ; cette exclusion doit être explicite dans la matrice et le README.
|
|
||||||
- Les stores exposent leurs comportements via les traits de `kb_store_core`.
|
|
||||||
- `kb_store_pg` est le store de production.
|
|
||||||
- `kb_store_sqlite` sert aux tests, imports et corpus locaux.
|
|
||||||
- `kb_wallet` reste isolé du reste du système.
|
|
||||||
- Les transactions raw sont immuables et restent la source d'audit.
|
|
||||||
- Les replays doivent être ciblés par module, version, programme, surface, discriminator, slot ou signatures.
|
|
||||||
- La documentation du projet ne doit pas référencer le nom de l'ancien workspace.
|
|
||||||
|
|
||||||
## Règles de documentation projet
|
|
||||||
|
|
||||||
- `README.md` décrit le projet, son rôle, ses objectifs et son organisation.
|
|
||||||
- `ROADMAP.md` contient les futures étapes, versions et changements prévus.
|
|
||||||
- `ROADMAP.md` conserve une structure documentaire normale par phases, cases cochées et journal de préversions ; les étiquettes conversationnelles de priorité ne doivent pas y être ajoutées.
|
|
||||||
- Les réponses de livraison doivent reprendre la liste exhaustive des tâches avec les rubriques conversationnelles **Validé**, **En cours**, **Next** et **Planifié**, sans réduire le suivi à un résumé ambigu.
|
|
||||||
- `CHANGELOG.md` n'est modifié qu'après validation d'une version, avec un paragraphe ajouté à la fin décrivant ce qui a été fait ou ajouté.
|
|
||||||
- Chaque crate Rust doit avoir un `README.md` ou `001.README.md` expliquant son rôle dans l'écosystème.
|
|
||||||
- Le README d'une crate opérationnelle doit inventorier ses types, traits, constantes et fonctions publics utiles, expliquer leurs paramètres, résultats, effets et frontières, puis fournir au moins un exemple d'utilisation lorsque l'API est destinée à être appelée directement.
|
|
||||||
- Une API publique ajoutée ou modifiée n'est pas considérée comme documentée tant que le README de sa crate n'a pas été synchronisé ; les bindings générés seuls ne remplacent pas cette documentation.
|
|
||||||
|
|
||||||
## Nomenclature métier
|
|
||||||
|
|
||||||
- `protocol_code` désigne la famille : `pump`, `raydium`, `meteora`, `orca`, `jupiter`, etc.
|
|
||||||
- `surface_code` désigne la surface concrète : `pump_swap`, `raydium_amm_v4`, `meteora_dlmm`, etc.
|
|
||||||
- `event_code` suit le format `<surface_code>.<event_name>`.
|
|
||||||
- Les familles d'événements principales sont : `trade`, `liquidity`, `lifecycle`, `fee`, `admin`, `reward`, `orderbook`, `token_account`, `pool_state`, `routing`, `risk`, `audit`, `unknown`.
|
|
||||||
|
|
||||||
## Base de données
|
|
||||||
|
|
||||||
- Les schémas PostgreSQL cibles sont : `raw`, `core`, `obs`, `decode`, `mat`, `catalog`, `agg`, `ops`, `wallet`.
|
|
||||||
- Les colonnes JSONB doivent se terminer par `_jsonb`.
|
|
||||||
- Les montants bruts on-chain doivent se terminer par `_raw`.
|
|
||||||
- La transaction canonique raw reste la source rejouable et ne doit pas être supprimée après traitement sans politique de rétention explicite.
|
|
||||||
|
|
||||||
## Nommage canonique des surfaces
|
|
||||||
|
|
||||||
Les nouvelles surfaces de programmes doivent utiliser un nom canonique basé sur la fonction réelle du programme :
|
|
||||||
|
|
||||||
```text
|
|
||||||
<function_code>_<family_code>_<identifier_code>[_vN]
|
|
||||||
```
|
|
||||||
|
|
||||||
Les crates de décodage doivent utiliser :
|
|
||||||
|
|
||||||
```text
|
|
||||||
kb_decoder_<function_code>_<family_code>_<identifier_code>[_vN]
|
|
||||||
```
|
|
||||||
|
|
||||||
Exemples :
|
|
||||||
|
|
||||||
- `kb_decoder_amm_raydium_cpmm` ;
|
|
||||||
- `kb_decoder_clmm_raydium` ;
|
|
||||||
- `kb_decoder_dlmm_meteora` ;
|
|
||||||
- `kb_decoder_router_jupiter_aggregator_v6` ;
|
|
||||||
- `kb_decoder_orderbook_openbook_v2` ;
|
|
||||||
- `kb_decoder_metadata_metaplex_token_metadata` ;
|
|
||||||
- `kb_decoder_nft_metaplex_bubblegum`.
|
|
||||||
|
|
||||||
Les noms historiques ou issus d'IDL doivent être conservés dans le registre, mais ne doivent pas créer de nouvelles crates si une crate canonique existe déjà.
|
|
||||||
|
|
||||||
Aucun renommage massif de crates n'est autorisé sans étape de contrôle dédiée et sans `cargo build` validé.
|
|
||||||
|
|
||||||
## Règles de nommage des surfaces Solana
|
|
||||||
|
|
||||||
- Le nom canonique d'une surface doit commencer par une fonction réelle : `amm`, `clmm`, `dlmm`, `router`, `orderbook`, `launchpad`, `lending`, `vault`, `staking`, `bridge`, `perpetuals`, `oracle`, `nft`, `metadata`, `admin`, etc.
|
|
||||||
- Le préfixe `program_` est interdit pour les nouveaux noms canoniques.
|
|
||||||
- Les surfaces non classifiées doivent utiliser `unknown_*` et ne doivent pas avoir de crate cible tant que leur fonction n'est pas validée.
|
|
||||||
- Les programmes Solana/SPL primitifs doivent rester séparés des surfaces DEX/router dans la documentation de contrôle.
|
|
||||||
- `damm` ne doit pas être utilisé comme préfixe fonctionnel ; utiliser `amm_meteora_damm_v1` ou `amm_meteora_damm_v2`.
|
|
||||||
|
|
||||||
## Registre des identifiants core
|
|
||||||
|
|
||||||
- Les identifiants Solana/SPL primitifs doivent être tenus à jour dans `registry/core_program_id_seed.toml`.
|
|
||||||
- Les sysvars et comptes natifs connus ne doivent pas être classés comme surfaces DEX/router.
|
|
||||||
- `spl_token`, `spl_token_2022` et `associated_token_account` restent dans leurs crates spécialisées.
|
|
||||||
- `stake_pool` doit être réservé à un futur crate spécialisé plutôt que mélangé avec le programme `stake`.
|
|
||||||
|
|
||||||
## Index court de programme
|
|
||||||
|
|
||||||
- Les noms de crates ne doivent pas commencer par un index hexadécimal.
|
|
||||||
- Un champ `registry_code` optionnel peut être ajouté au registre pour l'UI, PostgreSQL ou les matrices.
|
|
||||||
- Le nom canonique reste la source principale : fonction + famille + identifiant + version.
|
|
||||||
|
|
||||||
## Comptes non exécutables
|
|
||||||
|
|
||||||
- Une adresse de compte, de pool, de PDA ou de vault ne doit pas générer une crate de décodeur.
|
|
||||||
- Le vrai `program_id` propriétaire doit être prouvé avant création d'une surface canonique.
|
|
||||||
|
|
||||||
## Constantes Rust
|
|
||||||
|
|
||||||
- Les fichiers `program_ids.rs` sont interdits dans les nouveaux crates. Utiliser `constants.rs`.
|
|
||||||
- Les `program_id` publics doivent être réexportés depuis `lib.rs`.
|
|
||||||
- Dans une crate, les modules internes doivent appeler les constantes réexportées via `crate::CONSTANT_NAME`.
|
|
||||||
- Les discriminants, sélecteurs, longueurs Borsh et constantes internes futures doivent être placés dans `constants.rs` et rester `pub(crate)` sauf besoin d'API publique explicite.
|
|
||||||
|
|
||||||
## Règles de tracing
|
|
||||||
|
|
||||||
- Une crate est opérationnelle lorsqu’elle effectue des I/O, orchestre un pipeline, décode, matérialise, exécute, applique une politique runtime ou prend une décision mutable observable.
|
|
||||||
- Toute crate opérationnelle ajoutée ou modifiée doit dépendre de `tracing` depuis le workspace et déclarer exactement un `pub(crate) const TRACING_TARGET` dans `src/constants.rs`.
|
|
||||||
- La valeur canonique de `TRACING_TARGET_DECODER_METADATA_METAPLEX_TOKEN_METADATA` est le nom exact du package Cargo. Les targets historiques `khbot.*`, les suffixes de module et les targets de fenêtre sont interdits dans les nouvelles modifications.
|
|
||||||
- Les macros `tracing` doivent utiliser `target: crate::TRACING_TARGET` et des champs structurés stables. La granularité interne passe par `action`, `stage`, `window`, `campaign_id`, `signature`, `instruction_path`, `program_id`, `processor_name`, `processor_version`, `status` et `error_code`.
|
|
||||||
- Les crates passives de types, contrats, DTO, API sans exécution, registres ou constantes restent sans dépendance `tracing`. `kb_config` reste une exception de bootstrap tant que sa validation précède l’installation du subscriber.
|
|
||||||
- Il est interdit d’ajouter `tracing` sans événement réel ou de conserver un faux target uniquement consommé par `let _target`.
|
|
||||||
- Une décision interne doit être journalisée par la crate responsable ; `kb_app_demo` ne journalise que les frontières Tauri/UI, les actions utilisateur et les résumés d’orchestration.
|
|
||||||
- Tout input sélectionné sans décodeur compatible, tout résultat de décodage `failed` ou `unsupported`, tout résultat de matérialisation `failed`, toute validation de résultat invalide et toute erreur de persistance doivent émettre un événement `error` avant le retour ou la persistance terminale.
|
|
||||||
- Une transaction Solana échouée mais correctement décodée n’est pas une erreur du logiciel. Une décision `ignored`, un refus de matérialisation conforme à la politique ou une annulation coopérative ne doivent pas être promus artificiellement au niveau `error`.
|
|
||||||
- Les erreurs de décodage et de matérialisation doivent conserver au minimum, lorsque disponibles : `campaign_id`, `signature`, `slot`, `instruction_path`, `program_id`, processor ou materializer avec version, `input_key`, `input_hash` ou hash du payload, statut, code et diagnostic borné.
|
|
||||||
- Les payloads complets, DSN non masqués, secrets, clés privées et données non bornées sont interdits dans les logs.
|
|
||||||
- Chaque profil doit router les événements vers les sorties globales `debug.log`, `info.log`, `error.jsonl` et `app.log`, puis vers `debug.log`, `info.log` et `error.jsonl` dans un répertoire propre à chaque crate utilisant `tracing`.
|
|
||||||
- L’ajout ou la suppression de `tracing.workspace = true` dans une crate impose la mise à jour simultanée de la matrice de routes, de ses tests et de `docs/TRACING_CONTRACT.md`.
|
|
||||||
- Le contrat détaillé est défini dans `docs/TRACING_CONTRACT.md`.
|
|
||||||
- L’audit mécanique spécifique au projet est exécuté par `python3 scripts/audit_khadhroony_workspace_rules.py`. Il couvre notamment `TRACING_TARGET_DECODER_METADATA_METAPLEX_TOKEN_METADATA` et l’usage obligatoire de `solana_pubkey::Pubkey` à la place de `solana_address::Address`.
|
|
||||||
|
|
||||||
## Règles de réutilisation des interfaces Solana et SPL
|
|
||||||
|
|
||||||
- Les dépendances déclarées dans `[workspace.dependencies]` forment un catalogue de versions et de features autorisées ; elles ne doivent être ajoutées à une crate consommatrice que lorsqu’un type, un encodeur, un décodeur ou un identifiant officiel est réellement utilisé.
|
|
||||||
|
|
||||||
- Dans un `Cargo.toml`, placer dans `[dependencies]` toute crate référencée par le code de bibliothèque compilé en production. Réserver `[dev-dependencies]` aux références contenues exclusivement dans `#[cfg(test)]`, les tests d’intégration, benches ou exemples. Une dépendance de test vers un décodeur ou matérialiseur concret est légitime lorsqu’elle sert uniquement à éprouver une orchestration générique fondée sur les traits API ; elle ne prouve pas qu’une capacité de production manque. Toute promotion de `dev-dependencies` vers `dependencies` doit être motivée par un appel runtime réel, et toute dépendance runtime inutilisée doit être supprimée.
|
|
||||||
- Les registres de composition runtime des applications doivent énumérer explicitement chaque décodeur et matérialiseur concret activé. Toute nouvelle surface instructionnelle dotée d’un `MtApiEventMaterializer` doit être ajoutée au registre applicatif et couverte par un test d’inventaire ordonné ; une crate présente dans le workspace ou dans `kb_pipeline` n’est pas activée automatiquement. Les matérialiseurs exclusivement stateful qui n’implémentent pas `MtApiEventMaterializer` restent routés par leurs APIs de snapshots dédiées.
|
|
||||||
- Les corrélations instruction/état doivent produire une issue explicite (`confirmed`, `contradicted` ou `not_applicable`) et ne doivent jamais transformer automatiquement une configuration observée en violation, score ou conclusion métier.
|
|
||||||
- Une interface officielle Solana ou SPL étroite doit être préférée à `solana-sdk` lorsque son contrat suffit.
|
|
||||||
- L’ordre de préférence des formats est : schéma officiel `wincode`, schéma officiel Borsh, puis parseur local borné reproduisant exactement le runtime lorsque l’interface officielle n’expose que `bincode`.
|
|
||||||
- Aucun nouveau code ne doit dépendre directement de `bincode`. Une interface officielle uniquement disponible derrière une feature `bincode` ne justifie pas l’activation de cette feature ; le layout doit alors être prouvé depuis les sources officielles et implémenté localement avec des bornes et des tests.
|
|
||||||
- Les exécuteurs doivent utiliser les builders officiels disponibles, préserver l’ordre exact des metas, borner toute liste de comptes variable avant l’appel au builder et refuser les doublons lorsque leur répétition n’a pas de sémantique publiée.
|
|
||||||
- Les features des interfaces doivent rester minimales et explicites. Une feature `serde`, `wincode`, `borsh`, `std`, `alloc` ou équivalente n’est activée que si la crate consommatrice l’utilise réellement.
|
|
||||||
- Les crates applicatives ne doivent pas dépendre d’interfaces RPC ou transactionnelles uniquement pour relayer des types ; ces dépendances appartiennent à `kb_rpc`, aux modèles communs justifiés ou à la crate opérationnelle propriétaire.
|
|
||||||
- Toute exception et toute implémentation locale doivent être documentées dans `docs/SOLANA_INTERFACE_DEPENDENCIES.md` avec la raison, la source officielle et la stratégie de test.
|
|
||||||
|
|
||||||
## Règles des exécuteurs
|
|
||||||
|
|
||||||
- Les crates d'exécution utilisent le préfixe `kb_executor_`.
|
|
||||||
- Une surface classifiée peut avoir un décodeur `kb_decoder_<surface>` et un exécuteur `kb_executor_<surface>`.
|
|
||||||
- Les exécuteurs ne doivent pas dépendre des décodeurs.
|
|
||||||
- Les exécuteurs doivent passer par `kb_execution_api` pour leur contrat public.
|
|
||||||
- Les garde-fous communs doivent être placés dans `kb_execution_safety`.
|
|
||||||
- Aucun exécuteur ne doit envoyer de transaction sans simulation et validation explicite.
|
|
||||||
- Les surfaces non classifiées ne doivent pas avoir de crate exécuteur.
|
|
||||||
- Pour chaque programme Solana et contrairement aux décodeurs, les exécuteurs ne construisent pas les opérations obsolètes ou purement historiques. Ils couvrent uniquement les opérations courantes et expérimentales officiellement constructibles, avec un statut exact `Supported` ou `Unsupported(reason)`.
|
|
||||||
- Le statut expérimental, récent ou non encore déployé partout n'interdit pas un builder universel lorsqu'un wire officiel exact existe. Le déploiement, la simulation et l'autorisation d'envoi restent trois décisions séparées ; la bibliothèque ne doit pas imposer artificiellement un cluster.
|
|
||||||
|
|
||||||
|
|
||||||
- Les champs JSON exposés à TypeScript ne doivent pas utiliser directement `serde_json::Value` avec `TS-rs`; utiliser une chaîne JSON sérialisée (`std::string::String`) ou un type Rust typé exportable.
|
|
||||||
- Les APIs qui gardent des payloads dynamiques doivent fournir des helpers explicites basés sur `serde_json::to_string` et `serde_json::to_string_pretty`.
|
|
||||||
|
|
||||||
## Règles de configuration
|
|
||||||
|
|
||||||
- La configuration applicative commune doit passer par `kb_config`.
|
|
||||||
- Les fichiers JSON de configuration ne doivent pas contenir de commentaires.
|
|
||||||
- Les secrets ne doivent pas être écrits en clair dans le dépôt.
|
|
||||||
- Les valeurs sensibles doivent utiliser des variables d'environnement ou un stockage chiffré dédié.
|
|
||||||
- Les structures de configuration exposées à Tauri doivent dériver `TS`.
|
|
||||||
|
|
||||||
## Ordre de développement cible
|
|
||||||
|
|
||||||
- `kb_logging` doit être stabilisé avant les logs avancés des autres crates.
|
|
||||||
- `kb_config` doit être stabilisé avant les stores, RPC, wallet, applications et workers.
|
|
||||||
- Les contrats SQL et de matérialisation doivent être définis avant les gros décodeurs DEX.
|
|
||||||
- Les implémentations détaillées des matérialisateurs doivent suivre les sorties réelles des décodeurs correspondants.
|
|
||||||
- `kb_app_demo` doit fournir des validations live après chaque capacité majeure, sans créer une application Tauri séparée par crate.
|
|
||||||
|
|
||||||
## Règles de livraison ChatGPT
|
|
||||||
|
|
||||||
- Après le squelette initial, ChatGPT doit fournir uniquement des zips delta sauf demande explicite de zip complet.
|
|
||||||
- Un delta qui modifie la racine du workspace ou plusieurs modules doit être nommé `khadhroony-bot2_vX.Y.Z-pre.abc-delta.zip`.
|
|
||||||
- Un delta qui ne modifie qu'un seul module Rust doit être nommé `kb_modulename_vX.Y.Z-pre.abc-delta.zip`.
|
|
||||||
- Lorsqu'un delta `pre.abc` a déjà été livré et qu'un correctif est nécessaire, le numéro `abc` ne doit pas être incrémenté. Le correctif doit être nommé `khadhroony-bot2_vX.Y.Z-pre.abc-delta-fix-001.zip`, puis `-fix-002.zip`, etc. Pour un seul module, utiliser la même règle avec le préfixe `kb_modulename`.
|
|
||||||
- Un correctif doit indiquer dans `delta.md` le delta de base et les correctifs antérieurs à appliquer. Il ne doit pas réutiliser silencieusement le nom ou l'empreinte d'une archive déjà livrée.
|
|
||||||
- Le numéro `pre.abc` suivant est réservé à une nouvelle tranche fonctionnelle, pas à la réparation d'une archive existante.
|
|
||||||
- Chaque zip delta ou correctif doit contenir un fichier `delta.md` non versionné à la racine du zip.
|
|
||||||
- `delta.md` doit lister les fichiers ajoutés, les fichiers modifiés, les fichiers à supprimer manuellement, les validations exécutées et les validations non exécutées.
|
|
||||||
- Le zip delta ne doit pas contenir de fichiers inchangés.
|
|
||||||
- Le zip delta ne doit pas modifier `CHANGELOG.md` sauf validation explicite d'une version.
|
|
||||||
- Les suppressions de fichiers ou dossiers doivent être indiquées dans `delta.md`, car l'extraction d'un zip ne supprime pas automatiquement les anciens fichiers.
|
|
||||||
- Les prompts de session doivent rappeler ce format de livraison et la règle `delta-fix-NNN`.
|
|
||||||
|
|
||||||
## Constantes des décodeurs
|
|
||||||
|
|
||||||
- Chaque crate `kb_decoder_*` classifié avec un `program_id` doit avoir un fichier `src/constants.rs`.
|
|
||||||
- `src/constants.rs` contient les `PROGRAM_ID`, puis les discriminators, sélecteurs, opcodes, constantes Borsh et constantes de décodage quand elles seront connues.
|
|
||||||
- `src/lib.rs` doit réexporter les constantes nécessaires avec `pub use crate::constants::...`.
|
|
||||||
- `src/decoder.rs` doit utiliser les constantes réexportées par la crate, par exemple `crate::AMM_PUMP_SWAP_PROGRAM_ID`, et non `crate::constants::AMM_PUMP_SWAP_PROGRAM_ID`.
|
|
||||||
- Les literals de `program_id` ne doivent pas rester dans `program_ids()`, sauf dans un fichier `constants.rs`.
|
|
||||||
|
|
||||||
## Identifiants de programmes
|
|
||||||
|
|
||||||
Les `program_id` connus doivent être définis une seule fois dans `kb_program_ids`. Les crates de décodeur, d’exécuteur, de store, d’application ou d’outil doivent référencer directement `kb_program_ids::XXX_PROGRAM_ID`. Les fichiers `constants.rs` locaux ne doivent pas redéfinir ces chaînes ; ils restent réservés aux constantes internes du module, par exemple discriminators, opcodes, seeds, index de comptes ou layouts.
|
|
||||||
|
|
||||||
## Validation frontend Tauri
|
|
||||||
|
|
||||||
- Pour `kb_app_demo`, ne pas lancer `npm --prefix kb_app_demo run build` séparément : la validation frontend de développement est réalisée par `cargo tauri dev -c kb_app_demo/tauri.conf.json`, qui démarre et pilote le serveur Vite.
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
<!-- file: RUST_RULES.md -->
|
|
||||||
<!-- version: 3 -->
|
|
||||||
|
|
||||||
# Règles Rust générales
|
|
||||||
|
|
||||||
Ce fichier contient les règles normatives applicables à tous les projets Rust. Elles sont indépendantes de `khadhroony-bot2` et doivent pouvoir être réutilisées telles quelles dans un autre workspace.
|
|
||||||
|
|
||||||
## En-têtes et versions de fichiers
|
|
||||||
|
|
||||||
- Tout fichier texte qui supporte des commentaires commence par une ligne indiquant son chemin relatif dans le projet, puis une ligne `version` entière.
|
|
||||||
- La version d'un fichier est incrémentée à chaque modification après validation de sa version précédente.
|
|
||||||
- Les fichiers Rust utilisent `// file: ...` et `// version: N`.
|
|
||||||
- Les fichiers Markdown utilisent `<!-- file: ... -->` et `<!-- version: N -->`.
|
|
||||||
- Tous les fichiers texte se terminent par exactement une fin de ligne.
|
|
||||||
|
|
||||||
## Langue et documentation
|
|
||||||
|
|
||||||
- Les commentaires et rustdocs du code sont rédigés en anglais.
|
|
||||||
- Les documents Markdown du projet sont rédigés dans la langue documentaire choisie par le projet.
|
|
||||||
- Tout élément `pub` ou `pub(crate)` possède une rustdoc utile au point de déclaration.
|
|
||||||
- Toute réexportation `pub use` ou `pub(crate) use` dans `lib.rs` ou `main.rs` possède également sa propre rustdoc copiée ou reformulée de manière équivalente. La documentation du point d'entrée doit permettre de comprendre l'API sans ouvrir le module interne.
|
|
||||||
|
|
||||||
## Édition et lints obligatoires
|
|
||||||
|
|
||||||
- L'édition Rust cible est Rust 2024, sauf contrainte explicitement documentée.
|
|
||||||
- Chaque `lib.rs` et `main.rs` contient :
|
|
||||||
- `#![warn(missing_docs)]` ;
|
|
||||||
- `#![deny(unreachable_pub)]` ;
|
|
||||||
- `#![forbid(unsafe_code)]`.
|
|
||||||
- Les lints Clippy obligatoires sont déclarés au niveau workspace et hérités par toutes les crates.
|
|
||||||
- Les règles minimales sont : interdiction de `unwrap`, `expect`, `?`, retours implicites, code `unsafe`, APIs publiques inaccessibles et imports globaux non justifiés.
|
|
||||||
- Les tests peuvent disposer d'exceptions limitées pour `unwrap` et `expect` uniquement lorsqu'elles sont explicitement autorisées par la configuration Clippy.
|
|
||||||
|
|
||||||
La configuration workspace doit au minimum déclarer :
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[workspace.lints.rust]
|
|
||||||
missing_docs = "warn"
|
|
||||||
unreachable_pub = "deny"
|
|
||||||
unsafe_code = "forbid"
|
|
||||||
|
|
||||||
[workspace.lints.clippy]
|
|
||||||
unwrap_used = "deny"
|
|
||||||
expect_used = "deny"
|
|
||||||
implicit_return = "deny"
|
|
||||||
needless_return = "allow"
|
|
||||||
useless_vec = "deny"
|
|
||||||
question_mark = "deny"
|
|
||||||
question_mark_used = "deny"
|
|
||||||
needless_match = "allow"
|
|
||||||
manual_ok_err = "allow"
|
|
||||||
manual_unwrap_or = "allow"
|
|
||||||
manual_map = "allow"
|
|
||||||
match_like_matches_macro = "allow"
|
|
||||||
single_match = "allow"
|
|
||||||
manual_unwrap_or_default = "allow"
|
|
||||||
manual_find = "allow"
|
|
||||||
explicit_counter_loop = "allow"
|
|
||||||
get_first = "allow"
|
|
||||||
implicit_saturating_sub = "allow"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Formatage
|
|
||||||
|
|
||||||
- `cargo fmt --all` est exécuté après application de chaque delta ou correctif et avant les tests.
|
|
||||||
- Les fichiers Rust ne contiennent pas de lignes vides à l'intérieur d'une fonction, d'une structure, d'une énumération ou d'une implémentation courte.
|
|
||||||
- Les lignes vides séparent uniquement les fonctions, blocs `impl`, types et sections logiques.
|
|
||||||
- Les exports de `lib.rs` ou `main.rs` ne contiennent aucune ligne vide à l'intérieur d'une série homogène de `pub use` ou `pub(crate) use`.
|
|
||||||
- Les séries `pub use` et `pub(crate) use` forment deux groupes séparés lorsqu'elles coexistent.
|
|
||||||
|
|
||||||
## Imports et chemins
|
|
||||||
|
|
||||||
- `use` est interdit pour les constantes, fonctions, structures, énumérations, unions, alias de types, modules et macros.
|
|
||||||
- `use` est autorisé uniquement pour un trait lorsque la résolution de méthode, une macro de dérivation ou une contrainte de langage l'exige réellement.
|
|
||||||
- Un import de trait doit rester étroit et ne doit jamais importer simultanément des éléments non-traits par accolades.
|
|
||||||
- Les imports globaux, glob imports et imports groupés par accolades sont interdits.
|
|
||||||
- Pour un élément fourni par une crate externe au workspace, utiliser directement le chemin public le plus court exposé par cette crate. Exemple : utiliser `external_crate::Struct`, jamais `external_crate::module::Struct` si `external_crate::Struct` existe, et jamais `use external_crate::Struct`.
|
|
||||||
- Pour un élément `pub` déclaré dans le workspace :
|
|
||||||
- il est réexporté depuis le `lib.rs` ou `main.rs` de sa crate propriétaire ;
|
|
||||||
- depuis une autre crate, il est appelé via `owner_crate::Item` ;
|
|
||||||
- depuis sa propre crate, il est appelé via `crate::Item`, même depuis son module de déclaration.
|
|
||||||
- Pour un élément `pub(crate)` :
|
|
||||||
- il est réexporté depuis le `lib.rs` ou `main.rs` via `pub(crate) use` ;
|
|
||||||
- il est appelé via `crate::Item`, même depuis son module de déclaration.
|
|
||||||
- Un élément strictement privé à un module n'est pas réexporté et est appelé par son nom local uniquement. Il est interdit d'utiliser un chemin long comme `crate::module::helper` ou `owner_crate::module::helper` pour un helper privé du module courant.
|
|
||||||
- Dans un sous-module de tests, un élément privé du module parent est appelé via `super::Item`. Un élément `pub` ou `pub(crate)` continue d’être appelé via le point d’entrée de crate le plus court, par exemple `crate::Item`.
|
|
||||||
- Les exports ne sont jamais groupés avec des accolades. Un type, une fonction, une constante ou un alias correspond à une ligne de réexport distincte.
|
|
||||||
|
|
||||||
## Visibilité et API de crate
|
|
||||||
|
|
||||||
- Aucun `pub mod` n'est autorisé. Les modules restent privés et l'API est constituée par des réexports explicites.
|
|
||||||
- Un élément `pub` inaccessible depuis le point d'entrée de sa crate est une erreur de conception, pas un simple avertissement.
|
|
||||||
- Un élément `pub(crate)` utilisé hors de son module est réexporté au niveau du point d'entrée de la crate.
|
|
||||||
- Les chemins internes de modules ne font pas partie de l'API stable.
|
|
||||||
- Les méthodes inhérentes publiques restent appelées via le type réexporté ; les fonctions libres publiques sont appelées via le point d'entrée de crate.
|
|
||||||
|
|
||||||
## Helpers et réutilisation
|
|
||||||
|
|
||||||
- Un helper répété dans plusieurs modules d'une même crate est déplacé dans un module commun explicite, généralement `helper.rs` ou un module spécialisé plus précis.
|
|
||||||
- Le nom `helpers.rs` ou `helper.rs` n'est utilisé que si aucune responsabilité métier plus précise ne convient.
|
|
||||||
- Un helper général réutilisable par plusieurs crates est déplacé dans une crate commune appropriée et exposé publiquement.
|
|
||||||
- Les types d'erreur généraux, identifiants de programme, primitives de validation et fonctions de sérialisation communes ne doivent pas être dupliqués entre crates.
|
|
||||||
- La mutualisation ne doit pas créer de dépendance cyclique ni déplacer un comportement métier spécifique dans une crate générique.
|
|
||||||
|
|
||||||
## Gestion des erreurs et contrôle de flux
|
|
||||||
|
|
||||||
- `unwrap`, `expect` et `panic` sont interdits dans le code de production.
|
|
||||||
- L'opérateur `?` est interdit dans les chemins de production ; utiliser des `match` explicites avec erreurs contextualisées.
|
|
||||||
- `anyhow` et `thiserror` ne sont pas utilisés par défaut.
|
|
||||||
- Les erreurs publiques sont typées lorsque leur contrat est stable ; les diagnostics dynamiques restent bornés.
|
|
||||||
- Les retours sont explicites conformément au lint `clippy::implicit_return`.
|
|
||||||
|
|
||||||
## Sécurité et dépendances
|
|
||||||
|
|
||||||
- Le code `unsafe` est interdit.
|
|
||||||
- Une dépendance n'est ajoutée que si elle est réellement utilisée dans le chemin de compilation concerné.
|
|
||||||
- Une dépendance utilisée uniquement dans les tests reste dans `[dev-dependencies]`.
|
|
||||||
- Les features sont minimales et explicites.
|
|
||||||
|
|
||||||
## Contrôle avant livraison
|
|
||||||
|
|
||||||
Chaque livraison Rust exécute au minimum, dans cet ordre :
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cargo fmt --all
|
|
||||||
python3 scripts/audit_rust_general_rules.py
|
|
||||||
python3 scripts/audit_khadhroony_workspace_rules.py
|
|
||||||
cargo test --workspace
|
|
||||||
cargo clippy --workspace --all-targets
|
|
||||||
```
|
|
||||||
|
|
||||||
Un projet peut utiliser une sélection de tests plus étroite pendant le développement, mais la fermeture d'une version exige le contrôle global.
|
|
||||||
|
|
||||||
Le wrapper `python3 scripts/audit_rust_workspace_rules.py` exécute les deux audits sans fusionner leurs responsabilités.
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# file: kb-app-demo-desktop/Cargo.toml
|
# file: kb-app-demo-desktop/Cargo.toml
|
||||||
# version: 5
|
# version: 6
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "kb-app-demo-desktop"
|
name = "kb-app-demo-desktop"
|
||||||
@@ -21,7 +21,6 @@ path = "src/main.rs"
|
|||||||
tauri-build.workspace = true
|
tauri-build.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dotenvy.workspace = true
|
|
||||||
chrono.workspace = true
|
chrono.workspace = true
|
||||||
fs2.workspace = true
|
fs2.workspace = true
|
||||||
kb-config = { path = "../kb-config" }
|
kb-config = { path = "../kb-config" }
|
||||||
|
|||||||
@@ -1,26 +1,27 @@
|
|||||||
<!-- file: kb-app-demo-desktop/frontend/demo_backfill.html -->
|
<!-- file: kb-app-demo-desktop/frontend/demo_backfill.html -->
|
||||||
<!-- version: 3 -->
|
<!-- version: 5 -->
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||||
<title>Khadhroony Bot3 - Backfill HTTP</title>
|
<link rel="icon" href="imgs/favicon.png">
|
||||||
<link rel="stylesheet" href="sass/main.scss" />
|
<link rel="stylesheet" href="sass/main.scss">
|
||||||
|
<title>Khadhroony Bot3 — Backfill HTTP</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="bg-body-tertiary">
|
<body>
|
||||||
<header class="app-header">
|
<header class="app-header">
|
||||||
<nav class="navbar navbar-expand-lg h-100 py-0 bg-light text-dark">
|
<nav class="navbar navbar-expand-lg h-100 py-0 bg-light text-dark">
|
||||||
<div class="container my-0">
|
<div class="container-fluid px-4 my-0">
|
||||||
<a class="navbar-brand d-flex align-items-center" href="main.html">
|
<div class="navbar-brand d-flex align-items-center">
|
||||||
<img alt="Logo" src="imgs/logo.png" class="app-logo" />
|
<img alt="Logo" src="imgs/logo.png" class="app-logo" />
|
||||||
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Backfill HTTP</span>
|
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3 — <span class="badge text-bg-primary">Backfill HTTP</span></span>
|
||||||
</a>
|
</div>
|
||||||
<div class="ms-auto d-flex align-items-center gap-2">
|
<div class="ms-auto d-flex align-items-center gap-2">
|
||||||
<span id="backfillStatusBadge" class="badge text-bg-secondary">Initialisation</span>
|
<span class="badge text-bg-secondary" id="backfillStatusBadge">Initialisation</span>
|
||||||
<button id="cancelBackfillButton" class="btn btn-sm btn-outline-danger" type="button" disabled>Arrêter</button>
|
<button class="btn btn-sm btn-outline-danger" disabled="" id="cancelBackfillButton" type="button">Arrêter</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
@@ -28,154 +29,148 @@
|
|||||||
|
|
||||||
<main class="app-main">
|
<main class="app-main">
|
||||||
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
||||||
<div class="container py-4">
|
<div class="container-fluid px-4 py-4">
|
||||||
<div class="card shadow-sm border-0 mb-4">
|
<div class="row g-4 justify-content-center">
|
||||||
<div class="card-body">
|
<div class="col-12">
|
||||||
<h1 class="h3 card-title">Backfill transactionnel canonique</h1>
|
<div class="card shadow-sm border-0 mb-4">
|
||||||
<p class="text-body-secondary mb-0">Les signatures sont découvertes avec <code>getSignaturesForAddress</code>, hydratées avec <code>getTransaction</code>, puis stockées dans les tables canoniques et d'observation. Une seule campagne peut fonctionner à la fois.</p>
|
<div class="card-body">
|
||||||
</div>
|
<h1 class="h3 card-title">Backfill transactionnel canonique</h1>
|
||||||
</div>
|
<p class="text-body-secondary mb-0">Les signatures sont découvertes avec <code>getSignaturesForAddress</code>, hydratées avec <code>getTransaction</code>, puis stockées dans les tables canoniques et d'observation. Une seule campagne peut fonctionner à la fois.</p>
|
||||||
|
</div>
|
||||||
<div class="accordion shadow-sm" id="backfillAccordion">
|
</div>
|
||||||
<div class="accordion-item">
|
<div class="accordion shadow-sm" id="backfillAccordion">
|
||||||
<h2 class="accordion-header" id="sharedSettingsHeading">
|
<div class="accordion-item">
|
||||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#sharedSettingsCollapse" aria-expanded="true" aria-controls="sharedSettingsCollapse">Paramètres communs</button>
|
<h2 class="accordion-header" id="sharedSettingsHeading">
|
||||||
</h2>
|
<button aria-controls="sharedSettingsCollapse" aria-expanded="true" class="accordion-button" data-bs-target="#sharedSettingsCollapse" data-bs-toggle="collapse" type="button">Paramètres communs</button>
|
||||||
<div id="sharedSettingsCollapse" class="accordion-collapse collapse show" aria-labelledby="sharedSettingsHeading" data-bs-parent="#backfillAccordion">
|
</h2>
|
||||||
<div class="accordion-body">
|
<div aria-labelledby="sharedSettingsHeading" class="accordion-collapse collapse show" data-bs-parent="#backfillAccordion" id="sharedSettingsCollapse">
|
||||||
<div class="row g-3">
|
<div class="accordion-body">
|
||||||
<div class="col-12 col-md-6">
|
<div class="row g-3">
|
||||||
<label class="form-label" for="backfillRoleSelect">Rôle HTTP</label>
|
<div class="col-12 col-md-6">
|
||||||
<select id="backfillRoleSelect" class="form-select"></select>
|
<label class="form-label" for="backfillRoleSelect">Rôle HTTP</label>
|
||||||
|
<select class="form-select" id="backfillRoleSelect"></select>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<label class="form-label" for="backfillCommitmentSelect">Commitment</label>
|
||||||
|
<select class="form-select" id="backfillCommitmentSelect">
|
||||||
|
<option value="confirmed">confirmed</option>
|
||||||
|
<option value="finalized">finalized</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-6 col-lg-3">
|
||||||
|
<label class="form-label" for="backfillPageSizeInput">Taille de page</label>
|
||||||
|
<input class="form-control" id="backfillPageSizeInput" max="1000" min="1" type="number" />
|
||||||
|
</div>
|
||||||
|
<div class="col-6 col-lg-3">
|
||||||
|
<label class="form-label" for="backfillMaxPagesInput">Pages maximales</label>
|
||||||
|
<input class="form-control" id="backfillMaxPagesInput" min="1" type="number" />
|
||||||
|
</div>
|
||||||
|
<div class="col-6 col-lg-3">
|
||||||
|
<label class="form-label" for="backfillConcurrencyInput">Concurrence</label>
|
||||||
|
<input class="form-control" id="backfillConcurrencyInput" min="1" type="number" />
|
||||||
|
</div>
|
||||||
|
<div class="col-6 col-lg-3">
|
||||||
|
<label class="form-label" for="backfillRetriesInput">Retries</label>
|
||||||
|
<input class="form-control" id="backfillRetriesInput" min="0" type="number" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6">
|
</div>
|
||||||
<label class="form-label" for="backfillCommitmentSelect">Commitment</label>
|
</div>
|
||||||
<select id="backfillCommitmentSelect" class="form-select">
|
<div class="accordion-item">
|
||||||
<option value="confirmed">confirmed</option>
|
<h2 class="accordion-header" id="signatureBackfillHeading">
|
||||||
<option value="finalized">finalized</option>
|
<button aria-controls="signatureBackfillCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#signatureBackfillCollapse" data-bs-toggle="collapse" type="button">Ensemble de signatures</button>
|
||||||
</select>
|
</h2>
|
||||||
|
<div aria-labelledby="signatureBackfillHeading" class="accordion-collapse collapse" data-bs-parent="#backfillAccordion" id="signatureBackfillCollapse">
|
||||||
|
<div class="accordion-body">
|
||||||
|
<label class="form-label" for="explicitSignaturesTextarea">Signatures, une par ligne</label>
|
||||||
|
<textarea class="form-control font-monospace mb-3" id="explicitSignaturesTextarea" placeholder="5abc...
|
||||||
|
4def..." rows="10"></textarea>
|
||||||
|
<button class="btn btn-primary backfill-start-button" data-backfill-mode="explicit_signatures" type="button">Lancer le backfill</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 col-lg-3">
|
</div>
|
||||||
<label class="form-label" for="backfillPageSizeInput">Taille de page</label>
|
</div>
|
||||||
<input id="backfillPageSizeInput" class="form-control" type="number" min="1" max="1000" />
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="programBackfillHeading">
|
||||||
|
<button aria-controls="programBackfillCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#programBackfillCollapse" data-bs-toggle="collapse" type="button">Programme Solana</button>
|
||||||
|
</h2>
|
||||||
|
<div aria-labelledby="programBackfillHeading" class="accordion-collapse collapse" data-bs-parent="#backfillAccordion" id="programBackfillCollapse">
|
||||||
|
<div class="accordion-body">
|
||||||
|
<div class="row g-3 mb-3">
|
||||||
|
<div class="col-12"><label class="form-label" for="programAddressInput">Program ID</label><input class="form-control font-monospace" id="programAddressInput" /></div>
|
||||||
|
<div class="col-12"><label class="form-label" for="programAnchorInput">Signature d'ancrage</label><input class="form-control font-monospace" id="programAnchorInput" />
|
||||||
|
<div class="form-text">Optionnelle pour « Avant, plus anciennes » : vide, la recherche commence aux transactions les plus récentes. Obligatoire pour « Après, plus récentes ».</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-6"><label class="form-label" for="programDirectionSelect">Direction</label><select class="form-select" id="programDirectionSelect">
|
||||||
|
<option value="before">Avant, plus anciennes</option>
|
||||||
|
<option value="after">Après, plus récentes</option>
|
||||||
|
</select></div>
|
||||||
|
<div class="col-6"><label class="form-label" for="programLimitInput">Nombre de signatures</label><input class="form-control" id="programLimitInput" min="1" type="number" value="100" /></div>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-primary backfill-start-button" data-backfill-mode="program" type="button">Lancer le backfill programme</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 col-lg-3">
|
</div>
|
||||||
<label class="form-label" for="backfillMaxPagesInput">Pages maximales</label>
|
</div>
|
||||||
<input id="backfillMaxPagesInput" class="form-control" type="number" min="1" />
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="tokenBackfillHeading">
|
||||||
|
<button aria-controls="tokenBackfillCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#tokenBackfillCollapse" data-bs-toggle="collapse" type="button">Token</button>
|
||||||
|
</h2>
|
||||||
|
<div aria-labelledby="tokenBackfillHeading" class="accordion-collapse collapse" data-bs-parent="#backfillAccordion" id="tokenBackfillCollapse">
|
||||||
|
<div class="accordion-body">
|
||||||
|
<div class="row g-3 mb-3">
|
||||||
|
<div class="col-12"><label class="form-label" for="tokenAddressInput">Mint du token</label><input class="form-control font-monospace" id="tokenAddressInput" /></div>
|
||||||
|
<div class="col-12"><label class="form-label" for="tokenAnchorInput">Signature d'ancrage</label><input class="form-control font-monospace" id="tokenAnchorInput" />
|
||||||
|
<div class="form-text">Optionnelle pour « Avant, plus anciennes » : vide, la recherche commence aux transactions les plus récentes. Obligatoire pour « Après, plus récentes ».</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-6"><label class="form-label" for="tokenDirectionSelect">Direction</label><select class="form-select" id="tokenDirectionSelect">
|
||||||
|
<option value="before">Avant, plus anciennes</option>
|
||||||
|
<option value="after">Après, plus récentes</option>
|
||||||
|
</select></div>
|
||||||
|
<div class="col-6"><label class="form-label" for="tokenLimitInput">Nombre de signatures</label><input class="form-control" id="tokenLimitInput" min="1" type="number" value="100" /></div>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-primary backfill-start-button" data-backfill-mode="token" type="button">Lancer le backfill token</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 col-lg-3">
|
</div>
|
||||||
<label class="form-label" for="backfillConcurrencyInput">Concurrence</label>
|
</div>
|
||||||
<input id="backfillConcurrencyInput" class="form-control" type="number" min="1" />
|
<div class="accordion-item">
|
||||||
</div>
|
<h2 class="accordion-header" id="poolBackfillHeading">
|
||||||
<div class="col-6 col-lg-3">
|
<button aria-controls="poolBackfillCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#poolBackfillCollapse" data-bs-toggle="collapse" type="button">Pool</button>
|
||||||
<label class="form-label" for="backfillRetriesInput">Retries</label>
|
</h2>
|
||||||
<input id="backfillRetriesInput" class="form-control" type="number" min="0" />
|
<div aria-labelledby="poolBackfillHeading" class="accordion-collapse collapse" data-bs-parent="#backfillAccordion" id="poolBackfillCollapse">
|
||||||
|
<div class="accordion-body">
|
||||||
|
<div class="row g-3 mb-3">
|
||||||
|
<div class="col-12"><label class="form-label" for="poolAddressInput">Adresse du pool</label><input class="form-control font-monospace" id="poolAddressInput" /></div>
|
||||||
|
<div class="col-12"><label class="form-label" for="poolAnchorInput">Signature d'ancrage</label><input class="form-control font-monospace" id="poolAnchorInput" />
|
||||||
|
<div class="form-text">Optionnelle pour « Avant, plus anciennes » : vide, la recherche commence aux transactions les plus récentes. Obligatoire pour « Après, plus récentes ».</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-6"><label class="form-label" for="poolDirectionSelect">Direction</label><select class="form-select" id="poolDirectionSelect">
|
||||||
|
<option value="before">Avant, plus anciennes</option>
|
||||||
|
<option value="after">Après, plus récentes</option>
|
||||||
|
</select></div>
|
||||||
|
<div class="col-6"><label class="form-label" for="poolLimitInput">Nombre de signatures</label><input class="form-control" id="poolLimitInput" min="1" type="number" value="100" /></div>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-primary backfill-start-button" data-backfill-mode="pool" type="button">Lancer le backfill pool</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="card shadow-sm border-0 mt-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||||
|
<h2 class="h5 mb-0">Journal</h2>
|
||||||
|
|
||||||
<div class="accordion-item">
|
|
||||||
<h2 class="accordion-header" id="signatureBackfillHeading">
|
|
||||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#signatureBackfillCollapse" aria-expanded="false" aria-controls="signatureBackfillCollapse">Ensemble de signatures</button>
|
|
||||||
</h2>
|
|
||||||
<div id="signatureBackfillCollapse" class="accordion-collapse collapse" aria-labelledby="signatureBackfillHeading" data-bs-parent="#backfillAccordion">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<label class="form-label" for="explicitSignaturesTextarea">Signatures, une par ligne</label>
|
|
||||||
<textarea id="explicitSignaturesTextarea" class="form-control font-monospace mb-3" rows="10" placeholder="5abc... 4def..."></textarea>
|
|
||||||
<button class="btn btn-primary backfill-start-button" type="button" data-backfill-mode="explicit_signatures">Lancer le backfill</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="accordion-item">
|
|
||||||
<h2 class="accordion-header" id="programBackfillHeading">
|
|
||||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#programBackfillCollapse" aria-expanded="false" aria-controls="programBackfillCollapse">Programme Solana</button>
|
|
||||||
</h2>
|
|
||||||
<div id="programBackfillCollapse" class="accordion-collapse collapse" aria-labelledby="programBackfillHeading" data-bs-parent="#backfillAccordion">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<div class="row g-3 mb-3">
|
|
||||||
<div class="col-12"><label class="form-label" for="programAddressInput">Program ID</label><input id="programAddressInput" class="form-control font-monospace" /></div>
|
|
||||||
<div class="col-12"><label class="form-label" for="programAnchorInput">Signature d'ancrage</label><input id="programAnchorInput" class="form-control font-monospace" />
|
|
||||||
<div class="form-text">Optionnelle pour « Avant, plus anciennes » : vide, la recherche commence aux transactions les plus récentes. Obligatoire pour « Après, plus récentes ».</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-6"><label class="form-label" for="programDirectionSelect">Direction</label><select id="programDirectionSelect" class="form-select">
|
|
||||||
<option value="before">Avant, plus anciennes</option>
|
|
||||||
<option value="after">Après, plus récentes</option>
|
|
||||||
</select></div>
|
|
||||||
<div class="col-6"><label class="form-label" for="programLimitInput">Nombre de signatures</label><input id="programLimitInput" class="form-control" type="number" min="1" value="100" /></div>
|
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-primary backfill-start-button" type="button" data-backfill-mode="program">Lancer le backfill programme</button>
|
<textarea class="form-control font-monospace app-log-output mb-4" id="backfillLogOutput" readonly="">Aucune campagne exécutée.</textarea>
|
||||||
</div>
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||||
</div>
|
<h2 class="h5 mb-0">Résumé JSON</h2>
|
||||||
</div>
|
<button class="btn btn-sm btn-outline-primary" id="copyBackfillSummaryButton" type="button">Copier</button>
|
||||||
|
|
||||||
<div class="accordion-item">
|
|
||||||
<h2 class="accordion-header" id="tokenBackfillHeading">
|
|
||||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#tokenBackfillCollapse" aria-expanded="false" aria-controls="tokenBackfillCollapse">Token</button>
|
|
||||||
</h2>
|
|
||||||
<div id="tokenBackfillCollapse" class="accordion-collapse collapse" aria-labelledby="tokenBackfillHeading" data-bs-parent="#backfillAccordion">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<div class="row g-3 mb-3">
|
|
||||||
<div class="col-12"><label class="form-label" for="tokenAddressInput">Mint du token</label><input id="tokenAddressInput" class="form-control font-monospace" /></div>
|
|
||||||
<div class="col-12"><label class="form-label" for="tokenAnchorInput">Signature d'ancrage</label><input id="tokenAnchorInput" class="form-control font-monospace" />
|
|
||||||
<div class="form-text">Optionnelle pour « Avant, plus anciennes » : vide, la recherche commence aux transactions les plus récentes. Obligatoire pour « Après, plus récentes ».</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-6"><label class="form-label" for="tokenDirectionSelect">Direction</label><select id="tokenDirectionSelect" class="form-select">
|
|
||||||
<option value="before">Avant, plus anciennes</option>
|
|
||||||
<option value="after">Après, plus récentes</option>
|
|
||||||
</select></div>
|
|
||||||
<div class="col-6"><label class="form-label" for="tokenLimitInput">Nombre de signatures</label><input id="tokenLimitInput" class="form-control" type="number" min="1" value="100" /></div>
|
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-primary backfill-start-button" type="button" data-backfill-mode="token">Lancer le backfill token</button>
|
<div class="app-json-viewer" id="backfillSummaryOutput"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="accordion-item">
|
|
||||||
<h2 class="accordion-header" id="poolBackfillHeading">
|
|
||||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#poolBackfillCollapse" aria-expanded="false" aria-controls="poolBackfillCollapse">Pool</button>
|
|
||||||
</h2>
|
|
||||||
<div id="poolBackfillCollapse" class="accordion-collapse collapse" aria-labelledby="poolBackfillHeading" data-bs-parent="#backfillAccordion">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<div class="row g-3 mb-3">
|
|
||||||
<div class="col-12"><label class="form-label" for="poolAddressInput">Adresse du pool</label><input id="poolAddressInput" class="form-control font-monospace" /></div>
|
|
||||||
<div class="col-12"><label class="form-label" for="poolAnchorInput">Signature d'ancrage</label><input id="poolAnchorInput" class="form-control font-monospace" />
|
|
||||||
<div class="form-text">Optionnelle pour « Avant, plus anciennes » : vide, la recherche commence aux transactions les plus récentes. Obligatoire pour « Après, plus récentes ».</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-6"><label class="form-label" for="poolDirectionSelect">Direction</label><select id="poolDirectionSelect" class="form-select">
|
|
||||||
<option value="before">Avant, plus anciennes</option>
|
|
||||||
<option value="after">Après, plus récentes</option>
|
|
||||||
</select></div>
|
|
||||||
<div class="col-6"><label class="form-label" for="poolLimitInput">Nombre de signatures</label><input id="poolLimitInput" class="form-control" type="number" min="1" value="100" /></div>
|
|
||||||
</div>
|
|
||||||
<button class="btn btn-primary backfill-start-button" type="button" data-backfill-mode="pool">Lancer le backfill pool</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card shadow-sm border-0 mt-4">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
|
||||||
<h2 class="h5 mb-0">Journal</h2>
|
|
||||||
<div class="btn-group btn-group-sm">
|
|
||||||
<button id="copyBackfillLogButton" class="btn btn-outline-primary" type="button">Copier</button>
|
|
||||||
<button id="clearBackfillLogButton" class="btn btn-outline-secondary" type="button">Effacer</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<textarea id="backfillLogOutput" class="form-control font-monospace app-log-output mb-4" readonly>Aucune campagne exécutée.</textarea>
|
|
||||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
|
||||||
<h2 class="h5 mb-0">Résumé JSON</h2>
|
|
||||||
<button id="copyBackfillSummaryButton" class="btn btn-sm btn-outline-primary" type="button">Copier</button>
|
|
||||||
</div>
|
|
||||||
<div id="backfillSummaryOutput" class="app-json-viewer"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<footer class="app-footer bg-dark text-light">
|
<footer class="app-footer bg-dark text-light">
|
||||||
@@ -185,7 +180,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
<script type="module" src="ts/demo_backfill.ts" defer></script>
|
<script defer="" src="ts/demo_backfill.ts" type="module"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -1,26 +1,23 @@
|
|||||||
<!-- file: kb-app-demo-desktop/frontend/demo_config.html -->
|
<!-- file: kb-app-demo-desktop/frontend/demo_config.html -->
|
||||||
<!-- version: 3 -->
|
<!-- version: 4 -->
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||||
<title>Khadhroony Bot3 - Configuration</title>
|
<link rel="icon" href="imgs/favicon.png">
|
||||||
<link rel="stylesheet" href="sass/main.scss" />
|
<link rel="stylesheet" href="sass/main.scss">
|
||||||
|
<title>Khadhroony Bot3 — Configuration</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="bg-body-tertiary">
|
<body>
|
||||||
<header class="app-header">
|
<header class="app-header">
|
||||||
<nav class="navbar navbar-expand-lg h-100 py-0 bg-light text-dark">
|
<nav class="navbar navbar-expand-lg h-100 py-0 bg-light text-dark">
|
||||||
<div class="container my-0">
|
<div class="container-fluid px-4 my-0">
|
||||||
<div class="navbar-brand d-flex align-items-center" aria-label="Khadhroony Bot3">
|
<div class="navbar-brand d-flex align-items-center">
|
||||||
<img alt="Logo" src="imgs/logo.png" class="app-logo" />
|
<img alt="Logo" src="imgs/logo.png" class="app-logo">
|
||||||
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3</span>
|
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3 — <span class="badge text-bg-primary">Configuration</span></span>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="ms-auto d-flex align-items-center gap-2">
|
|
||||||
<span class="badge text-bg-primary">Configuration</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
@@ -28,8 +25,8 @@
|
|||||||
|
|
||||||
<main class="app-main">
|
<main class="app-main">
|
||||||
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
||||||
<div class="container py-4">
|
<div class="container-fluid px-4 py-4">
|
||||||
<div class="row g-4">
|
<div class="row g-4 justify-content-center">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="card shadow-sm border-0">
|
<div class="card shadow-sm border-0">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@@ -80,14 +77,11 @@
|
|||||||
<footer class="app-footer bg-dark text-light">
|
<footer class="app-footer bg-dark text-light">
|
||||||
<div class="container h-100 d-flex align-items-center">
|
<div class="container h-100 d-flex align-items-center">
|
||||||
<div class="row flex-grow-1 align-items-center">
|
<div class="row flex-grow-1 align-items-center">
|
||||||
<div class="col-12 text-center text-small my-1 my-md-0">
|
<div class="col-12 text-center text-small my-1 my-md-0">© 2026 SASEDEV</div>
|
||||||
© 2026 SASEDEV
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script type="module" src="ts/demo_config.ts" defer></script>
|
<script type="module" src="ts/demo_config.ts" defer></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -1,30 +1,31 @@
|
|||||||
<!-- file: kb_app_demo/frontend/demo_core_extraction.html -->
|
<!-- file: kb-app-demo-desktop/frontend/demo_core_extraction.html -->
|
||||||
<!-- version: 4 -->
|
<!-- version: 7 -->
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||||
<title>Khadhroony Bot2 - Extraction canonical vers core</title>
|
<link rel="icon" href="imgs/favicon.png">
|
||||||
<link rel="stylesheet" href="sass/main.scss" />
|
<link rel="stylesheet" href="sass/main.scss">
|
||||||
|
<title>Khadhroony Bot3 — Extraction canonical vers core</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="bg-body-tertiary">
|
<body>
|
||||||
<header class="app-header">
|
<header class="app-header">
|
||||||
<nav class="navbar navbar-expand-lg h-100 py-0 bg-light text-dark">
|
<nav class="navbar navbar-expand-lg h-100 py-0 bg-light text-dark">
|
||||||
<div class="container my-0">
|
<div class="container-fluid px-4 my-0">
|
||||||
<div class="navbar-brand d-flex align-items-center" aria-label="Khadhroony Bot3">
|
<div class="navbar-brand d-flex align-items-center">
|
||||||
<img alt="Logo" src="imgs/logo.png" class="app-logo" />
|
<img alt="Logo" src="imgs/logo.png" class="app-logo">
|
||||||
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Extraction core</span>
|
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3 — <span class="badge text-bg-primary">Extraction core</span></span>
|
||||||
</a>
|
</div>
|
||||||
<div class="ms-auto d-flex align-items-center gap-2">
|
<div class="ms-auto d-flex align-items-center gap-2">
|
||||||
<span id="coreExtractionVersionBadge" class="badge text-bg-info">Version —</span>
|
<span class="badge text-bg-info" id="coreExtractionVersionBadge">Version —</span>
|
||||||
<span id="coreExtractionStatusBadge" class="badge text-bg-secondary">Initialisation</span>
|
<span class="badge text-bg-secondary" id="coreExtractionStatusBadge">Initialisation</span>
|
||||||
<button id="openRawDiagnosticsButton" class="btn btn-sm btn-outline-secondary" type="button">Diagnostic raw</button>
|
<button class="btn btn-sm btn-outline-secondary" id="openRawDiagnosticsButton" type="button">Diagnostic raw</button>
|
||||||
<button id="openCoreDiagnosticsButton" class="btn btn-sm btn-outline-secondary" type="button">Diagnostic core</button>
|
<button class="btn btn-sm btn-outline-secondary" id="openCoreDiagnosticsButton" type="button">Diagnostic core</button>
|
||||||
<button id="openReplayCandidatesButton" class="btn btn-sm btn-outline-primary" type="button">Candidats replay</button>
|
<button class="btn btn-sm btn-outline-primary" id="openReplayCandidatesButton" type="button">Candidats replay</button>
|
||||||
<button id="cancelCoreExtractionButton" class="btn btn-sm btn-outline-danger" type="button" disabled>Arrêter</button>
|
<button class="btn btn-sm btn-outline-danger" disabled="" id="cancelCoreExtractionButton" type="button">Arrêter</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
@@ -32,119 +33,114 @@
|
|||||||
|
|
||||||
<main class="app-main">
|
<main class="app-main">
|
||||||
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
||||||
<div class="container py-4">
|
<div class="container-fluid px-4 py-4">
|
||||||
<div class="card shadow-sm border-0 mb-4">
|
<div class="row g-4 justify-content-center">
|
||||||
<div class="card-body">
|
<div class="col-12">
|
||||||
<h1 class="h3 card-title">Extraction transactionnelle canonical vers core</h1>
|
<div class="card shadow-sm border-0 mb-4">
|
||||||
<p class="text-body-secondary mb-0">Chaque transaction canonique sélectionnée est validée, normalisée dans les tables core et enregistrée dans le ledger de traitement au sein d'une seule transaction PostgreSQL.</p>
|
<div class="card-body">
|
||||||
</div>
|
<h1 class="h3 card-title">Extraction transactionnelle canonical vers core</h1>
|
||||||
</div>
|
<p class="text-body-secondary mb-0">Chaque transaction canonique sélectionnée est validée, normalisée dans les tables core et enregistrée dans le ledger de traitement au sein d'une seule transaction PostgreSQL.</p>
|
||||||
|
</div>
|
||||||
<div class="accordion shadow-sm" id="coreExtractionAccordion">
|
</div>
|
||||||
<div class="accordion-item">
|
<div class="accordion shadow-sm" id="coreExtractionAccordion">
|
||||||
<h2 class="accordion-header" id="coreExtractionSettingsHeading">
|
<div class="accordion-item">
|
||||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#coreExtractionSettingsCollapse" aria-expanded="true" aria-controls="coreExtractionSettingsCollapse">Paramètres communs</button>
|
<h2 class="accordion-header" id="coreExtractionSettingsHeading">
|
||||||
</h2>
|
<button aria-controls="coreExtractionSettingsCollapse" aria-expanded="true" class="accordion-button" data-bs-target="#coreExtractionSettingsCollapse" data-bs-toggle="collapse" type="button">Paramètres communs</button>
|
||||||
<div id="coreExtractionSettingsCollapse" class="accordion-collapse collapse show" aria-labelledby="coreExtractionSettingsHeading" data-bs-parent="#coreExtractionAccordion">
|
</h2>
|
||||||
<div class="accordion-body">
|
<div aria-labelledby="coreExtractionSettingsHeading" class="accordion-collapse collapse show" data-bs-parent="#coreExtractionAccordion" id="coreExtractionSettingsCollapse">
|
||||||
<div class="row g-3 align-items-end">
|
<div class="accordion-body">
|
||||||
<div class="col-6 col-lg-4">
|
<div class="row g-3 align-items-end">
|
||||||
<label class="form-label" for="coreExtractionLimitInput">Transactions maximales</label>
|
<div class="col-6 col-lg-4">
|
||||||
<input id="coreExtractionLimitInput" class="form-control" type="number" min="1" />
|
<label class="form-label" for="coreExtractionLimitInput">Transactions maximales</label>
|
||||||
</div>
|
<input class="form-control" id="coreExtractionLimitInput" min="1" type="number" />
|
||||||
<div class="col-6 col-lg-4">
|
</div>
|
||||||
<label class="form-label" for="coreExtractionConcurrencyInput">Concurrence</label>
|
<div class="col-6 col-lg-4">
|
||||||
<input id="coreExtractionConcurrencyInput" class="form-control" type="number" min="1" />
|
<label class="form-label" for="coreExtractionConcurrencyInput">Concurrence</label>
|
||||||
</div>
|
<input class="form-control" id="coreExtractionConcurrencyInput" min="1" type="number" />
|
||||||
<div class="col-12 col-lg-4">
|
</div>
|
||||||
<div class="form-check form-switch mb-2">
|
<div class="col-12 col-lg-4">
|
||||||
<input id="coreExtractionForceReplayInput" class="form-check-input" type="checkbox" role="switch" />
|
<div class="form-check form-switch mb-2">
|
||||||
<label class="form-check-label" for="coreExtractionForceReplayInput">Forcer le remplacement des lignes déjà à jour</label>
|
<input class="form-check-input" id="coreExtractionForceReplayInput" role="switch" type="checkbox" />
|
||||||
|
<label class="form-check-label" for="coreExtractionForceReplayInput">Forcer le remplacement des lignes déjà à jour</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="accordion-item">
|
||||||
</div>
|
<h2 class="accordion-header" id="coreExtractionSignaturesHeading">
|
||||||
|
<button aria-controls="coreExtractionSignaturesCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#coreExtractionSignaturesCollapse" data-bs-toggle="collapse" type="button">Signatures explicites</button>
|
||||||
<div class="accordion-item">
|
</h2>
|
||||||
<h2 class="accordion-header" id="coreExtractionSignaturesHeading">
|
<div aria-labelledby="coreExtractionSignaturesHeading" class="accordion-collapse collapse" data-bs-parent="#coreExtractionAccordion" id="coreExtractionSignaturesCollapse">
|
||||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#coreExtractionSignaturesCollapse" aria-expanded="false" aria-controls="coreExtractionSignaturesCollapse">Signatures explicites</button>
|
<div class="accordion-body">
|
||||||
</h2>
|
<label class="form-label" for="coreExtractionSignaturesTextarea">Signatures canoniques déjà stockées, une par ligne</label>
|
||||||
<div id="coreExtractionSignaturesCollapse" class="accordion-collapse collapse" aria-labelledby="coreExtractionSignaturesHeading" data-bs-parent="#coreExtractionAccordion">
|
<textarea class="form-control font-monospace mb-3" id="coreExtractionSignaturesTextarea" placeholder="5abc...
|
||||||
<div class="accordion-body">
|
4def..." rows="10"></textarea>
|
||||||
<label class="form-label" for="coreExtractionSignaturesTextarea">Signatures canoniques déjà stockées, une par ligne</label>
|
<button class="btn btn-primary core-extraction-start-button" data-core-extraction-mode="signatures" type="button">Extraire les signatures</button>
|
||||||
<textarea id="coreExtractionSignaturesTextarea" class="form-control font-monospace mb-3" rows="10" placeholder="5abc... 4def..."></textarea>
|
|
||||||
<button class="btn btn-primary core-extraction-start-button" type="button" data-core-extraction-mode="signatures">Extraire les signatures</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="accordion-item">
|
|
||||||
<h2 class="accordion-header" id="coreExtractionPendingHeading">
|
|
||||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#coreExtractionPendingCollapse" aria-expanded="false" aria-controls="coreExtractionPendingCollapse">Transactions en attente</button>
|
|
||||||
</h2>
|
|
||||||
<div id="coreExtractionPendingCollapse" class="accordion-collapse collapse" aria-labelledby="coreExtractionPendingHeading" data-bs-parent="#coreExtractionAccordion">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<p class="text-body-secondary">Sélectionne les transactions canoniques dont l'état de traitement est <code>received</code>, dans l'ordre des slots.</p>
|
|
||||||
<button class="btn btn-primary core-extraction-start-button" type="button" data-core-extraction-mode="pending">Extraire les transactions en attente</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="accordion-item">
|
|
||||||
<h2 class="accordion-header" id="coreExtractionSlotsHeading">
|
|
||||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#coreExtractionSlotsCollapse" aria-expanded="false" aria-controls="coreExtractionSlotsCollapse">Plage de slots</button>
|
|
||||||
</h2>
|
|
||||||
<div id="coreExtractionSlotsCollapse" class="accordion-collapse collapse" aria-labelledby="coreExtractionSlotsHeading" data-bs-parent="#coreExtractionAccordion">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<div class="row g-3 mb-3">
|
|
||||||
<div class="col-12 col-md-6">
|
|
||||||
<label class="form-label" for="coreExtractionMinSlotInput">Slot minimum inclusif</label>
|
|
||||||
<input id="coreExtractionMinSlotInput" class="form-control" type="number" min="0" />
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-md-6">
|
|
||||||
<label class="form-label" for="coreExtractionMaxSlotInput">Slot maximum inclusif</label>
|
|
||||||
<input id="coreExtractionMaxSlotInput" class="form-control" type="number" min="0" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-primary core-extraction-start-button" type="button" data-core-extraction-mode="slot_range">Extraire la plage de slots</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="accordion-item">
|
||||||
</div>
|
<h2 class="accordion-header" id="coreExtractionPendingHeading">
|
||||||
|
<button aria-controls="coreExtractionPendingCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#coreExtractionPendingCollapse" data-bs-toggle="collapse" type="button">Transactions en attente</button>
|
||||||
<div class="accordion-item">
|
</h2>
|
||||||
<h2 class="accordion-header" id="coreExtractionProgramHeading">
|
<div aria-labelledby="coreExtractionPendingHeading" class="accordion-collapse collapse" data-bs-parent="#coreExtractionAccordion" id="coreExtractionPendingCollapse">
|
||||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#coreExtractionProgramCollapse" aria-expanded="false" aria-controls="coreExtractionProgramCollapse">Programme déjà indexé dans core</button>
|
<div class="accordion-body">
|
||||||
</h2>
|
<p class="text-body-secondary">Sélectionne les transactions canoniques dont l'état de traitement est <code>received</code>, dans l'ordre des slots.</p>
|
||||||
<div id="coreExtractionProgramCollapse" class="accordion-collapse collapse" aria-labelledby="coreExtractionProgramHeading" data-bs-parent="#coreExtractionAccordion">
|
<button class="btn btn-primary core-extraction-start-button" data-core-extraction-mode="pending" type="button">Extraire les transactions en attente</button>
|
||||||
<div class="accordion-body">
|
</div>
|
||||||
<p class="text-body-secondary">Sélectionne les transactions raw ayant déjà au moins une instruction core résolue pour ce programme. Ce mode sert aux replays après changement de version ou de hash.</p>
|
</div>
|
||||||
<label class="form-label" for="coreExtractionProgramIdInput">Program ID</label>
|
</div>
|
||||||
<input id="coreExtractionProgramIdInput" class="form-control font-monospace mb-3" />
|
<div class="accordion-item">
|
||||||
<button class="btn btn-primary core-extraction-start-button" type="button" data-core-extraction-mode="program_id">Extraire par programme</button>
|
<h2 class="accordion-header" id="coreExtractionSlotsHeading">
|
||||||
|
<button aria-controls="coreExtractionSlotsCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#coreExtractionSlotsCollapse" data-bs-toggle="collapse" type="button">Plage de slots</button>
|
||||||
|
</h2>
|
||||||
|
<div aria-labelledby="coreExtractionSlotsHeading" class="accordion-collapse collapse" data-bs-parent="#coreExtractionAccordion" id="coreExtractionSlotsCollapse">
|
||||||
|
<div class="accordion-body">
|
||||||
|
<div class="row g-3 mb-3">
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<label class="form-label" for="coreExtractionMinSlotInput">Slot minimum inclusif</label>
|
||||||
|
<input class="form-control" id="coreExtractionMinSlotInput" min="0" type="number" />
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<label class="form-label" for="coreExtractionMaxSlotInput">Slot maximum inclusif</label>
|
||||||
|
<input class="form-control" id="coreExtractionMaxSlotInput" min="0" type="number" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-primary core-extraction-start-button" data-core-extraction-mode="slot_range" type="button">Extraire la plage de slots</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="coreExtractionProgramHeading">
|
||||||
|
<button aria-controls="coreExtractionProgramCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#coreExtractionProgramCollapse" data-bs-toggle="collapse" type="button">Programme déjà indexé dans core</button>
|
||||||
|
</h2>
|
||||||
|
<div aria-labelledby="coreExtractionProgramHeading" class="accordion-collapse collapse" data-bs-parent="#coreExtractionAccordion" id="coreExtractionProgramCollapse">
|
||||||
|
<div class="accordion-body">
|
||||||
|
<p class="text-body-secondary">Sélectionne les transactions raw ayant déjà au moins une instruction core résolue pour ce programme. Ce mode sert aux replays après changement de version ou de hash.</p>
|
||||||
|
<label class="form-label" for="coreExtractionProgramIdInput">Program ID</label>
|
||||||
|
<input class="form-control font-monospace mb-3" id="coreExtractionProgramIdInput" />
|
||||||
|
<button class="btn btn-primary core-extraction-start-button" data-core-extraction-mode="program_id" type="button">Extraire par programme</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="accordion-item">
|
</div>
|
||||||
<h2 class="accordion-header" id="coreExtractionLogHeading">
|
<div class="card shadow-sm border-0 mt-4">
|
||||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#coreExtractionLogCollapse" aria-expanded="false" aria-controls="coreExtractionLogCollapse">Journal et résultat</button>
|
<div class="card-body">
|
||||||
</h2>
|
<h2 class="h5 mb-3">Journal et résultat</h2>
|
||||||
<div id="coreExtractionLogCollapse" class="accordion-collapse collapse" aria-labelledby="coreExtractionLogHeading" data-bs-parent="#coreExtractionAccordion">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||||
<h3 class="h6 mb-0">Journal</h3><button id="clearCoreExtractionLogButton" class="btn btn-sm btn-outline-secondary" type="button">Effacer</button>
|
<h3 class="h6 mb-0">Journal</h3>
|
||||||
</div>
|
</div>
|
||||||
<textarea id="coreExtractionLogOutput" class="form-control font-monospace mb-3" rows="15" readonly>Aucune campagne exécutée.</textarea>
|
<textarea class="form-control font-monospace mb-3" id="coreExtractionLogOutput" readonly="" rows="15">Aucune campagne exécutée.</textarea>
|
||||||
<h3 class="h6">Résumé JSON</h3>
|
<h3 class="h6">Résumé JSON</h3>
|
||||||
<textarea id="coreExtractionSummaryOutput" class="form-control font-monospace" rows="16" readonly data-json-viewer="true">Aucun résultat.</textarea>
|
<textarea class="form-control font-monospace" data-json-viewer="true" id="coreExtractionSummaryOutput" readonly="" rows="16">Aucun résultat.</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<footer class="app-footer bg-dark text-light">
|
<footer class="app-footer bg-dark text-light">
|
||||||
@@ -154,7 +150,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
<script type="module" src="ts/demo_core_extraction.ts" defer></script>
|
<script defer="" src="ts/demo_core_extraction.ts" type="module"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -1,22 +1,25 @@
|
|||||||
<!-- file: kb_app_demo/frontend/demo_decode_replay.html -->
|
<!-- file: kb_app_demo/frontend/demo_decode_replay.html -->
|
||||||
<!-- version: 4 -->
|
<!-- version: 5 -->
|
||||||
<!doctype html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr" data-bs-theme="light">
|
<html lang="fr">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||||
<title>Décodage et matérialisation</title>
|
<link rel="icon" href="imgs/favicon.png">
|
||||||
<link rel="icon" href="imgs/favicon.png" />
|
<link rel="stylesheet" href="sass/main.scss">
|
||||||
<link rel="stylesheet" href="sass/main.scss" />
|
<title>Khadhroony Bot3 — Décodage et matérialisation</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="bg-body-tertiary">
|
<body>
|
||||||
<header class="app-header">
|
<header class="app-header">
|
||||||
<nav class="navbar h-100 py-0 bg-light text-dark">
|
<nav class="navbar navbar-expand-lg h-100 py-0 bg-light text-dark">
|
||||||
<div class="container-fluid px-4">
|
<div class="container-fluid px-4 my-0">
|
||||||
<div class="navbar-brand d-flex align-items-center" aria-label="Khadhroony Bot3"><img alt="Logo Khadhroony" src="imgs/logo.png" class="app-logo" /><span class="ps-2 fs-4 fw-bold text-primary font-logo">Décodage contextualisé</span></div>
|
<div class="navbar-brand d-flex align-items-center">
|
||||||
<div class="d-flex align-items-center gap-2">
|
<img alt="Logo" src="imgs/logo.png" class="app-logo">
|
||||||
|
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3 — <span class="badge text-bg-primary">Décodage contextualisé</span></span>
|
||||||
|
</div>
|
||||||
|
<div class="ms-auto d-flex align-items-center gap-2">
|
||||||
<span id="decodeReplayVersionBadge" class="badge text-bg-secondary">Version</span>
|
<span id="decodeReplayVersionBadge" class="badge text-bg-secondary">Version</span>
|
||||||
<span id="decodeReplayStatusBadge" class="badge text-bg-success">Prêt</span>
|
<span id="decodeReplayStatusBadge" class="badge text-bg-success">Prêt</span>
|
||||||
<button id="cancelDecodeReplayButton" class="btn btn-sm btn-outline-danger" type="button" disabled>Arrêter</button>
|
<button id="cancelDecodeReplayButton" class="btn btn-sm btn-outline-danger" type="button" disabled>Arrêter</button>
|
||||||
@@ -24,11 +27,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main class="app-main">
|
<main class="app-main">
|
||||||
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
||||||
<div class="container-fluid px-4 py-4">
|
<div class="container-fluid px-4 py-4">
|
||||||
<div class="row g-4">
|
<div class="row g-4 justify-content-center">
|
||||||
<div class="col-12 col-xl-7">
|
<div class="col-12">
|
||||||
<div class="card shadow-sm border-0 mb-4">
|
<div class="card shadow-sm border-0 mb-4">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h1 class="h4 mb-3">Sélection bornée</h1>
|
<h1 class="h4 mb-3">Sélection bornée</h1>
|
||||||
@@ -157,10 +161,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<footer class="app-footer bg-dark text-light">
|
<footer class="app-footer bg-dark text-light">
|
||||||
<div class="container h-100 d-flex align-items-center justify-content-center">© 2026 SASEDEV</div>
|
<div class="container h-100 d-flex align-items-center">
|
||||||
|
<div class="row flex-grow-1 align-items-center">
|
||||||
|
<div class="col-12 text-center text-small my-1 my-md-0">© 2026 SASEDEV</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
<script type="module" src="ts/demo_decode_replay.ts" defer></script>
|
<script type="module" src="ts/demo_decode_replay.ts" defer></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -1,78 +1,102 @@
|
|||||||
<!-- file: kb-app-demo-desktop/frontend/demo_execution_solana_core.html -->
|
<!-- file: kb-app-demo-desktop/frontend/demo_execution_solana_core.html -->
|
||||||
<!-- version: 7 -->
|
<!-- version: 9 -->
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
<head>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
|
||||||
<title>Exécution Solana Core Devnet</title>
|
|
||||||
<link href="sass/main.scss" rel="stylesheet"/>
|
|
||||||
</head>
|
|
||||||
<body class="app-body">
|
|
||||||
<header class="app-header bg-dark text-light">
|
|
||||||
<nav class="container-fluid h-100 d-flex align-items-center justify-content-between px-4">
|
|
||||||
<div class="navbar-brand d-flex align-items-center mb-0">
|
|
||||||
<img alt="Logo Khadhroony" src="imgs/logo.png" class="app-logo"/>
|
|
||||||
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3</span>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex align-items-center gap-2"><span class="badge text-bg-success" id="executionStatusBadge">Prêt</span><button class="btn btn-sm btn-outline-warning" disabled="" id="cancelExecutionButton" type="button">Annuler</button></div>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
<main class="app-main">
|
|
||||||
<div class="osb-scrollable pt-1 pb-4" data-simplebar="">
|
|
||||||
<div class="container-fluid py-4 px-4">
|
|
||||||
<div class="card shadow-sm border-0 mb-4"><div class="card-body">
|
|
||||||
<h1 class="h3 card-title mb-2">Exécution Solana Core Devnet</h1>
|
|
||||||
<p class="text-body-secondary mb-0">System Program uniquement — simulation-first et replay post-exécution.</p>
|
|
||||||
</div></div>
|
|
||||||
<div class="alert alert-warning">Cette fenêtre est strictement réservée aux opérations Solana Core. Les opérations SPL sont disponibles dans « Exécution SPL Devnet ».</div>
|
|
||||||
<div class="row g-4">
|
|
||||||
<div class="col-12 col-xl-5">
|
|
||||||
<div class="card shadow-sm border-0"><div class="card-body"><div class="d-flex flex-wrap align-items-center justify-content-between gap-2 mb-3"><h2 class="h5 mb-0">System Program</h2><span class="badge text-bg-primary">solana_native_classifier</span></div>
|
|
||||||
|
|
||||||
<div class="mb-3"><label class="form-label" for="executionProfileSelect">Profil Devnet</label><select class="form-select" id="executionProfileSelect"></select>
|
<head>
|
||||||
<div class="form-text" id="executionProfileHelp"></div>
|
<meta charset="utf-8">
|
||||||
</div>
|
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||||
<div class="mb-3"><label class="form-label" for="executionRecipientInput">Destinataire</label>
|
<link rel="icon" href="imgs/favicon.png">
|
||||||
<div class="input-group"><input autocomplete="off" class="form-control font-monospace" id="executionRecipientInput" type="text"/><button class="btn btn-outline-secondary" id="generateRecipientButton" type="button">Générer</button></div>
|
<link rel="stylesheet" href="sass/main.scss">
|
||||||
</div>
|
<title>Khadhroony Bot3 — Exécution Solana Core Devnet</title>
|
||||||
<div class="row g-3">
|
</head>
|
||||||
<div class="col-6"><label class="form-label" for="executionLamportsInput">Lamports</label><input class="form-control" id="executionLamportsInput" min="1" step="1" type="number"/></div>
|
|
||||||
<div class="col-6"><label class="form-label" for="executionAirdropInput">Airdrop maximal</label><input class="form-control" id="executionAirdropInput" min="0" step="1" type="number" value="0"/></div>
|
<body>
|
||||||
</div>
|
<header class="app-header">
|
||||||
<hr/>
|
<nav class="navbar navbar-expand-lg h-100 py-0 bg-dark text-ligh">
|
||||||
<div class="form-check form-switch mb-2"><input class="form-check-input" id="executionOperatorConfirmedInput" type="checkbox"/><label class="form-check-label" for="executionOperatorConfirmedInput">Confirmation opérateur explicite</label></div>
|
<div class="container-fluid px-4 my-0">
|
||||||
<div class="form-check form-switch mb-2"><input class="form-check-input" id="executionForceReplayInput" type="checkbox"/><label class="form-check-label" for="executionForceReplayInput">Forcer le replay post-exécution</label></div>
|
<div class="navbar-brand d-flex align-items-center">
|
||||||
<div class="form-check form-switch mb-3"><input class="form-check-input" id="executionMaterializeInput" type="checkbox"/><label class="form-check-label" for="executionMaterializeInput">Matérialiser après décodage</label></div>
|
<img alt="Logo" src="imgs/logo.png" class="app-logo">
|
||||||
<div class="d-grid gap-2 d-md-flex"><button class="btn btn-outline-primary flex-fill" id="simulateExecutionButton" type="button">Simuler uniquement</button><button class="btn btn-danger flex-fill" id="submitExecutionButton" type="button">Signer et envoyer</button></div>
|
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3 — <span class="badge text-bg-primary">Exécution Solana Core Devnet</span></span>
|
||||||
</div></div>
|
</div>
|
||||||
<div class="card shadow-sm border-0 mt-4">
|
<div class="ms-auto d-flex align-items-center gap-2">
|
||||||
<div class="card-body">
|
<span class="badge text-bg-success" id="executionStatusBadge">Prêt</span><button class="btn btn-sm btn-outline-warning" disabled="" id="cancelExecutionButton" type="button">Annuler</button>
|
||||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
</div>
|
||||||
<h2 class="h5 mb-0">Journal</h2><button class="btn btn-sm btn-outline-secondary" id="clearExecutionLogButton" type="button">Effacer</button>
|
</div>
|
||||||
</div><textarea class="form-control font-monospace" id="executionLogOutput" readonly="" rows="18"></textarea>
|
</nav>
|
||||||
</div>
|
</header>
|
||||||
</div>
|
|
||||||
</div>
|
<main class="app-main">
|
||||||
<div class="col-12 col-xl-7">
|
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
||||||
<div class="card shadow-sm border-0">
|
<div class="container-fluid px-4 py-4">
|
||||||
<div class="card-body">
|
<div class="row g-4 justify-content-center">
|
||||||
<h2 class="h5 mb-3">Résumé</h2><textarea class="form-control font-monospace" id="executionSummaryOutput" readonly="" rows="14" data-json-viewer="true">Aucun résultat.</textarea>
|
<div class="col-12">
|
||||||
</div>
|
<div class="card shadow-sm border-0 mb-4">
|
||||||
</div>
|
<div class="card-body">
|
||||||
<div class="card shadow-sm border-0 mt-4">
|
<h1 class="h3 card-title mb-2">System Program uniquement — simulation-first et replay post-exécution.</h1>
|
||||||
<div class="card-body">
|
</div>
|
||||||
<h2 class="h5">Plan exact</h2><textarea class="form-control font-monospace" id="executionPlanOutput" readonly="" rows="12" data-json-viewer="true">Aucun plan.</textarea>
|
</div>
|
||||||
<h2 class="h5 mt-3">Simulation exacte</h2><textarea class="form-control font-monospace" id="executionSimulationOutput" readonly="" rows="12" data-json-viewer="true">Aucune simulation.</textarea>
|
<div class="alert alert-warning">Cette fenêtre est strictement réservée aux opérations Solana Core. Les opérations SPL sont disponibles dans « Exécution SPL Devnet ».</div>
|
||||||
<h2 class="h5 mt-3">Confirmation et replay</h2><textarea class="form-control font-monospace" id="executionDiagnosticsOutput" readonly="" rows="12" data-json-viewer="true">Aucun diagnostic.</textarea>
|
<div class="row g-4">
|
||||||
</div>
|
<div class="col-12 col-xl-5">
|
||||||
</div>
|
<div class="card shadow-sm border-0">
|
||||||
</div>
|
<div class="card-body">
|
||||||
</div>
|
<div class="d-flex flex-wrap align-items-center justify-content-between gap-2 mb-3">
|
||||||
</div>
|
<h2 class="h5 mb-0">System Program</h2><span class="badge text-bg-primary">solana_native_classifier</span>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
<div class="mb-3"><label class="form-label" for="executionProfileSelect">Profil Devnet</label><select class="form-select" id="executionProfileSelect"></select>
|
||||||
<script defer="" src="ts/demo_execution_solana_core.ts" type="module"></script>
|
<div class="form-text" id="executionProfileHelp"></div>
|
||||||
</body>
|
</div>
|
||||||
</html>
|
<div class="mb-3"><label class="form-label" for="executionRecipientInput">Destinataire</label>
|
||||||
|
<div class="input-group"><input autocomplete="off" class="form-control font-monospace" id="executionRecipientInput" type="text" /><button class="btn btn-outline-secondary" id="generateRecipientButton" type="button">Générer</button></div>
|
||||||
|
</div>
|
||||||
|
<div class="row g-3">
|
||||||
|
<div class="col-6"><label class="form-label" for="executionLamportsInput">Lamports</label><input class="form-control" id="executionLamportsInput" min="1" step="1" type="number" /></div>
|
||||||
|
<div class="col-6"><label class="form-label" for="executionAirdropInput">Airdrop maximal</label><input class="form-control" id="executionAirdropInput" min="0" step="1" type="number" value="0" /></div>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<div class="form-check form-switch mb-2"><input class="form-check-input" id="executionOperatorConfirmedInput" type="checkbox" /><label class="form-check-label" for="executionOperatorConfirmedInput">Confirmation opérateur explicite</label></div>
|
||||||
|
<div class="form-check form-switch mb-2"><input class="form-check-input" id="executionForceReplayInput" type="checkbox" /><label class="form-check-label" for="executionForceReplayInput">Forcer le replay post-exécution</label></div>
|
||||||
|
<div class="form-check form-switch mb-3"><input class="form-check-input" id="executionMaterializeInput" type="checkbox" /><label class="form-check-label" for="executionMaterializeInput">Matérialiser après décodage</label></div>
|
||||||
|
<div class="d-grid gap-2 d-md-flex"><button class="btn btn-outline-primary flex-fill" id="simulateExecutionButton" type="button">Simuler uniquement</button><button class="btn btn-danger flex-fill" id="submitExecutionButton" type="button">Signer et envoyer</button></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card shadow-sm border-0 mt-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||||
|
<h2 class="h5 mb-0">Journal</h2>
|
||||||
|
</div><textarea class="form-control font-monospace" id="executionLogOutput" readonly="" rows="18"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-xl-7">
|
||||||
|
<div class="card shadow-sm border-0">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="h5 mb-3">Résumé</h2><textarea class="form-control font-monospace" data-json-viewer="true" id="executionSummaryOutput" readonly="" rows="14">Aucun résultat.</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card shadow-sm border-0 mt-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="h5">Plan exact</h2><textarea class="form-control font-monospace" data-json-viewer="true" id="executionPlanOutput" readonly="" rows="12">Aucun plan.</textarea>
|
||||||
|
<h2 class="h5 mt-3">Simulation exacte</h2><textarea class="form-control font-monospace" data-json-viewer="true" id="executionSimulationOutput" readonly="" rows="12">Aucune simulation.</textarea>
|
||||||
|
<h2 class="h5 mt-3">Confirmation et replay</h2><textarea class="form-control font-monospace" data-json-viewer="true" id="executionDiagnosticsOutput" readonly="" rows="12">Aucun diagnostic.</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="app-footer bg-dark text-light">
|
||||||
|
<div class="container h-100 d-flex align-items-center">
|
||||||
|
<div class="row flex-grow-1 align-items-center">
|
||||||
|
<div class="col-12 text-center text-small my-1 my-md-0">© 2026 SASEDEV</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
<script defer="" src="ts/demo_execution_solana_core.ts" type="module"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -1,431 +1,442 @@
|
|||||||
<!-- file: kb-app-demo-desktop/frontend/demo_execution_spl.html -->
|
<!-- file: kb-app-demo-desktop/frontend/demo_execution_spl.html -->
|
||||||
<!-- version: 9 -->
|
<!-- version: 11 -->
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8">
|
||||||
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||||
<title>Exécution SPL Devnet</title>
|
<link rel="icon" href="imgs/favicon.png">
|
||||||
<link href="sass/main.scss" rel="stylesheet" />
|
<link rel="stylesheet" href="sass/main.scss">
|
||||||
|
<title>Khadhroony Bot3 — Exécution SPL Devnet</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="app-body">
|
<body>
|
||||||
<header class="app-header bg-dark text-light">
|
<header class="app-header">
|
||||||
<nav class="container-fluid h-100 d-flex align-items-center justify-content-between px-4">
|
<nav class="navbar navbar-expand-lg h-100 py-0 bg-dark text-ligh">
|
||||||
<div class="navbar-brand d-flex align-items-center mb-0">
|
<div class="container-fluid px-4 my-0">
|
||||||
<img alt="Logo Khadhroony" src="imgs/logo.png" class="app-logo" />
|
<div class="navbar-brand d-flex align-items-center">
|
||||||
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3</span>
|
<img alt="Logo" src="imgs/logo.png" class="app-logo">
|
||||||
</div>
|
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3 — <span class="badge text-bg-primary">Exécution SPL Devnet</span></span>
|
||||||
<div class="d-flex align-items-center gap-2">
|
</div>
|
||||||
<span class="badge text-bg-success" id="executionStatusBadge">Prêt</span>
|
<div class="ms-auto d-flex align-items-center gap-2">
|
||||||
<button class="btn btn-sm btn-outline-warning" disabled="" id="cancelExecutionButton" type="button">Annuler</button>
|
<span class="badge text-bg-success" id="executionStatusBadge">Prêt</span>
|
||||||
|
<button class="btn btn-sm btn-outline-warning" disabled="" id="cancelExecutionButton" type="button">Annuler</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main class="app-main">
|
<main class="app-main">
|
||||||
<div class="osb-scrollable pt-1 pb-4" data-simplebar="">
|
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
||||||
<div class="container-fluid py-4 px-4">
|
<div class="container-fluid px-4 py-4">
|
||||||
<div class="card shadow-sm border-0 mb-4"><div class="card-body">
|
<div class="row g-4 justify-content-center">
|
||||||
<h1 class="h3 card-title mb-2">Exécution SPL Devnet</h1>
|
<div class="col-12">
|
||||||
<p class="text-body-secondary mb-0">Memo, SPL Token classique, Token-2022 et ATA — simulation-first et replay post-exécution.</p>
|
<div class="card shadow-sm border-0 mb-4">
|
||||||
</div></div>
|
<div class="card-body">
|
||||||
<div class="alert alert-warning" role="alert">
|
<h1 class="h3 card-title mb-2">Memo, SPL Token classique, Token-2022 et ATA — simulation-first et replay post-exécution.</h1>
|
||||||
Cette fenêtre est limitée à Devnet. La clé privée du wallet source reste dans le backend Rust et n’est jamais transmise à la WebView.
|
|
||||||
</div>
|
|
||||||
<div class="row g-4" id="splExecutionWorkspace">
|
|
||||||
<div class="col-12 col-xl-5" id="splExecutionControls">
|
|
||||||
<div class="accordion shadow-sm" id="walletPreparationAccordion">
|
|
||||||
<div class="accordion-item">
|
|
||||||
<h2 class="accordion-header" id="walletPreparationHeading"><button aria-controls="walletPreparationCollapse" aria-expanded="true" class="accordion-button" data-bs-target="#walletPreparationCollapse" data-bs-toggle="collapse" type="button"><span class="d-flex flex-wrap align-items-center justify-content-between gap-2 w-100 me-2"><span>Préparation commune du wallet Devnet</span><span class="badge text-bg-info">Pré-requis</span></span></button></h2>
|
|
||||||
<div aria-labelledby="walletPreparationHeading" class="accordion-collapse collapse show" id="walletPreparationCollapse">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label" for="executionProfileSelect">Profil Devnet</label>
|
|
||||||
<select class="form-select" id="executionProfileSelect"></select>
|
|
||||||
<div class="form-text" id="executionProfileHelp"></div>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label" for="executionRecipientInput">Destinataire</label>
|
|
||||||
<div class="input-group">
|
|
||||||
<input autocomplete="off" class="form-control font-monospace" id="executionRecipientInput" type="text" />
|
|
||||||
<button class="btn btn-outline-secondary" id="generateRecipientButton" type="button">Générer</button>
|
|
||||||
</div>
|
|
||||||
<div class="form-text">Une adresse générée ici est jetable : sa clé privée n’est ni conservée ni exposée.</div>
|
|
||||||
</div>
|
|
||||||
<div class="row g-3">
|
|
||||||
<div class="col-12 col-md-6">
|
|
||||||
<label class="form-label" for="executionLamportsInput">Lamports transférés</label>
|
|
||||||
<input class="form-control" id="executionLamportsInput" min="1" step="1" type="number" />
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-md-6">
|
|
||||||
<label class="form-label" for="executionAirdropInput">Airdrop maximal</label>
|
|
||||||
<input class="form-control" id="executionAirdropInput" min="0" step="1" type="number" value="0" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr />
|
|
||||||
<div class="form-check form-switch mb-2">
|
|
||||||
<input class="form-check-input" id="executionOperatorConfirmedInput" type="checkbox" />
|
|
||||||
<label class="form-check-label" for="executionOperatorConfirmedInput">Confirmation opérateur explicite</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-check form-switch mb-2">
|
|
||||||
<input class="form-check-input" id="executionForceReplayInput" type="checkbox" />
|
|
||||||
<label class="form-check-label" for="executionForceReplayInput">Forcer le replay post-exécution</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-check form-switch mb-3">
|
|
||||||
<input class="form-check-input" id="executionMaterializeInput" type="checkbox" />
|
|
||||||
<label class="form-check-label" for="executionMaterializeInput">Matérialiser après décodage</label>
|
|
||||||
</div>
|
|
||||||
<div class="d-grid gap-2 d-md-flex">
|
|
||||||
<button class="btn btn-outline-primary flex-fill" id="simulateExecutionButton" type="button">Simuler uniquement</button>
|
|
||||||
<button class="btn btn-danger flex-fill" id="submitExecutionButton" type="button">Signer et envoyer</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex align-items-center justify-content-between mt-4 mb-2">
|
<div class="alert alert-warning" role="alert">
|
||||||
<h2 class="h5 mb-0">Exécutions par décodeur</h2><small class="text-body-secondary">Ouvrir une seule famille à la fois</small>
|
Cette fenêtre est limitée à Devnet. La clé privée du wallet source reste dans le backend Rust et n’est jamais transmise à la WebView.
|
||||||
</div>
|
</div>
|
||||||
<div class="accordion shadow-sm mt-4" id="decoderExecutionAccordion">
|
<div class="row g-4" id="splExecutionWorkspace">
|
||||||
<div class="accordion-item">
|
<div class="col-12 col-xl-5" id="splExecutionControls">
|
||||||
<h2 class="accordion-header" id="splMemoDecoderHeading"><button aria-controls="splMemoDecoderCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#splMemoDecoderCollapse" data-bs-toggle="collapse" type="button"><span class="d-flex flex-wrap align-items-center justify-content-between gap-2 w-100 me-2"><span>Décodeur spl_memo — Memo v4</span><span class="badge text-bg-primary">Exécutable</span></span></button></h2>
|
<div class="accordion shadow-sm" id="walletPreparationAccordion">
|
||||||
<div aria-labelledby="splMemoDecoderHeading" class="accordion-collapse collapse" data-bs-parent="#decoderExecutionAccordion" id="splMemoDecoderCollapse">
|
<div class="accordion-item">
|
||||||
<div class="accordion-body">
|
<h2 class="accordion-header" id="walletPreparationHeading"><button aria-controls="walletPreparationCollapse" aria-expanded="true" class="accordion-button" data-bs-target="#walletPreparationCollapse" data-bs-toggle="collapse" type="button"><span class="d-flex flex-wrap align-items-center justify-content-between gap-2 w-100 me-2"><span>Préparation commune du wallet Devnet</span><span class="badge text-bg-info">Pré-requis</span></span></button></h2>
|
||||||
<div class="mb-3">
|
<div aria-labelledby="walletPreparationHeading" class="accordion-collapse collapse show" id="walletPreparationCollapse">
|
||||||
<label class="form-label" for="memoMessageInput">Annotation UTF-8 exacte</label>
|
<div class="accordion-body">
|
||||||
<textarea class="form-control" id="memoMessageInput" maxlength="566" rows="5">khadhroony-bot2 Memo v4 validation</textarea>
|
<div class="mb-3">
|
||||||
<div class="form-text">566 octets UTF-8 maximum. La matérialisation `transaction_annotation` et le second replay d’idempotence sont obligatoires après envoi.</div>
|
<label class="form-label" for="executionProfileSelect">Profil Devnet</label>
|
||||||
</div>
|
<select class="form-select" id="executionProfileSelect"></select>
|
||||||
<div class="form-check form-switch mb-3">
|
<div class="form-text" id="executionProfileHelp"></div>
|
||||||
<input checked="" class="form-check-input" id="memoWalletSignerInput" type="checkbox" />
|
|
||||||
<label class="form-check-label" for="memoWalletSignerInput">Inclure le wallet comme signer Memo readonly</label>
|
|
||||||
</div>
|
|
||||||
<div class="alert alert-secondary py-2 small" role="note">
|
|
||||||
Ce parcours réutilise le profil, la confirmation opérateur et l’option de force replay du panneau System ci-dessus. Aucune clé privée ne traverse la WebView.
|
|
||||||
</div>
|
|
||||||
<div class="d-grid gap-2 d-md-flex">
|
|
||||||
<button class="btn btn-outline-info flex-fill" id="simulateMemoButton" type="button">Simuler Memo</button>
|
|
||||||
<button class="btn btn-danger flex-fill" id="submitMemoButton" type="button">Signer et envoyer Memo</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="accordion-item">
|
|
||||||
<h2 class="accordion-header" id="splTokenDecoderHeading"><button aria-controls="splTokenDecoderCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#splTokenDecoderCollapse" data-bs-toggle="collapse" type="button"><span class="d-flex flex-wrap align-items-center justify-content-between gap-2 w-100 me-2"><span>Décodeur spl_token — TransferChecked</span><span class="badge text-bg-primary">Exécutable</span></span></button></h2>
|
|
||||||
<div aria-labelledby="splTokenDecoderHeading" class="accordion-collapse collapse" data-bs-parent="#decoderExecutionAccordion" id="splTokenDecoderCollapse">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<div class="alert alert-secondary py-2 small" role="note">
|
|
||||||
Le mint et les decimals sont explicites. Le préflight vérifie les deux comptes, le solde et l’autorité avant toute simulation. L’envoi réutilise le profil et la confirmation opérateur communs.
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label" for="tokenSourceInput">Compte source</label>
|
|
||||||
<input autocomplete="off" class="form-control font-monospace" id="tokenSourceInput" type="text" />
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label" for="tokenMintInput">Mint</label>
|
|
||||||
<input autocomplete="off" class="form-control font-monospace" id="tokenMintInput" type="text" />
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label" for="tokenDestinationInput">Compte destination</label>
|
|
||||||
<input autocomplete="off" class="form-control font-monospace" id="tokenDestinationInput" type="text" />
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label" for="tokenAuthorityInput">Autorité simple</label>
|
|
||||||
<input autocomplete="off" class="form-control font-monospace" id="tokenAuthorityInput" type="text" />
|
|
||||||
<div class="form-text">Doit correspondre au wallet persistant du profil pour un envoi.</div>
|
|
||||||
</div>
|
|
||||||
<div class="row g-3 mb-3">
|
|
||||||
<div class="col-12 col-md-7">
|
|
||||||
<label class="form-label" for="tokenAmountRawInput">Montant brut exact</label>
|
|
||||||
<input class="form-control font-monospace" id="tokenAmountRawInput" inputmode="numeric" type="text" value="1" />
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-md-5">
|
|
||||||
<label class="form-label" for="tokenDecimalsInput">Decimals</label>
|
|
||||||
<input class="form-control" id="tokenDecimalsInput" max="255" min="0" step="1" type="number" value="9" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="d-grid gap-2 d-md-flex">
|
|
||||||
<button class="btn btn-outline-primary flex-fill" id="simulateTokenButton" type="button">Préflight et simuler</button>
|
|
||||||
<button class="btn btn-danger flex-fill" id="submitTokenButton" type="button">Signer et envoyer Token</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="accordion-item">
|
|
||||||
<h2 class="accordion-header" id="splAtaDecoderHeading"><button aria-controls="splAtaDecoderCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#splAtaDecoderCollapse" data-bs-toggle="collapse" type="button"><span class="d-flex flex-wrap align-items-center justify-content-between gap-2 w-100 me-2"><span>Décodeur spl_associated_token_account — Create / CreateIdempotent</span><span class="badge text-bg-primary">Exécutable</span></span></button></h2>
|
|
||||||
<div aria-labelledby="splAtaDecoderHeading" class="accordion-collapse collapse" data-bs-parent="#decoderExecutionAccordion" id="splAtaDecoderCollapse">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<div class="row g-3 mb-3">
|
|
||||||
<div class="col-12 col-md-6">
|
|
||||||
<label class="form-label" for="ataTokenProgramSelect">Token Program cible</label>
|
|
||||||
<select class="form-select" id="ataTokenProgramSelect">
|
|
||||||
<option value="classic">SPL Token classique</option>
|
|
||||||
<option value="token2022">Token-2022</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-md-6">
|
|
||||||
<label class="form-label" for="ataModeSelect">Mode</label>
|
|
||||||
<select class="form-select" id="ataModeSelect">
|
|
||||||
<option value="create_idempotent">CreateIdempotent</option>
|
|
||||||
<option value="create">Create</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label" for="ataMintInput">Mint</label>
|
|
||||||
<input autocomplete="off" class="form-control font-monospace" id="ataMintInput" type="text" />
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label" for="ataPayerInput">Payer readonly</label>
|
|
||||||
<input class="form-control font-monospace" id="ataPayerInput" readonly="" type="text" />
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label" for="ataWalletOwnerInput">Wallet owner readonly</label>
|
|
||||||
<input class="form-control font-monospace" id="ataWalletOwnerInput" readonly="" type="text" />
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label" for="ataDerivedInput">ATA dérivé readonly</label>
|
|
||||||
<input class="form-control font-monospace" id="ataDerivedInput" readonly="" type="text" />
|
|
||||||
<div class="form-text">Actualisé depuis le backend avec les seeds wallet, Token Program et mint.</div>
|
|
||||||
</div>
|
|
||||||
<div class="d-grid gap-2 d-md-flex">
|
|
||||||
<button class="btn btn-outline-secondary flex-fill" id="deriveAtaButton" type="button">Dériver</button>
|
|
||||||
<button class="btn btn-outline-primary flex-fill" id="simulateAtaButton" type="button">Préflight et simuler</button>
|
|
||||||
<button class="btn btn-danger flex-fill" id="submitAtaButton" type="button">Confirmer et envoyer</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="accordion-item">
|
|
||||||
<h2 class="accordion-header" id="splToken2022DecoderHeading"><button aria-controls="splToken2022DecoderCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#splToken2022DecoderCollapse" data-bs-toggle="collapse" type="button"><span class="d-flex flex-wrap align-items-center justify-content-between gap-2 w-100 me-2"><span>Exécution spl_token2022 — scénarios publics</span><span class="badge text-bg-success">Exécutable</span></span></button></h2>
|
|
||||||
<div aria-labelledby="splToken2022DecoderHeading" class="accordion-collapse collapse" data-bs-parent="#decoderExecutionAccordion" id="splToken2022DecoderCollapse">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<div class="alert alert-info">Chaque opération est simulée sur le message exact avant toute signature. Les scénarios sont indépendants et réutilisent la fixture chargée dans les deux terminaux.</div>
|
|
||||||
<div class="d-grid mb-3"><button class="btn btn-outline-secondary" id="loadToken2022FixtureButton" type="button">Charger la fixture Token-2022</button></div>
|
|
||||||
<div class="form-text mb-3" id="token2022FixtureHelp">Aucune fixture chargée.</div>
|
|
||||||
<div class="mb-3"><label class="form-label" for="token2022ScenarioSelect">Scénario</label><select class="form-select" id="token2022ScenarioSelect">
|
|
||||||
<option value="token2022_mint_to_checked">MintToChecked</option>
|
|
||||||
<option value="token2022_transfer_checked">TransferChecked</option>
|
|
||||||
<option value="token2022_approve_checked">ApproveChecked</option>
|
|
||||||
<option value="token2022_revoke">Revoke</option>
|
|
||||||
<option value="token2022_burn_checked">BurnChecked</option>
|
|
||||||
<option value="token2022_freeze_account">FreezeAccount</option>
|
|
||||||
<option value="token2022_thaw_account">ThawAccount</option>
|
|
||||||
<option value="token2022_close_destination">CloseAccount</option>
|
|
||||||
</select></div>
|
|
||||||
<div class="mb-3"><label class="form-label" for="token2022SourceInput">Compte source / compte cible</label><input class="form-control font-monospace" id="token2022SourceInput" type="text" /></div>
|
|
||||||
<div class="mb-3"><label class="form-label" for="token2022MintInput">Mint Token-2022</label><input class="form-control font-monospace" id="token2022MintInput" type="text" /></div>
|
|
||||||
<div class="mb-3"><label class="form-label" for="token2022DestinationInput">Compte destination / destination lamports</label><input class="form-control font-monospace" id="token2022DestinationInput" type="text" /></div>
|
|
||||||
<div class="mb-3"><label class="form-label" for="token2022DelegateInput">Delegate</label><input class="form-control font-monospace" id="token2022DelegateInput" type="text" /></div>
|
|
||||||
<div class="mb-3"><label class="form-label" for="token2022AuthorityInput">Autorité</label><input class="form-control font-monospace" id="token2022AuthorityInput" type="text" /></div>
|
|
||||||
<div class="mb-3"><label class="form-label" for="token2022FreezeAuthorityInput">Freeze authority</label><input class="form-control font-monospace" id="token2022FreezeAuthorityInput" type="text" /></div>
|
|
||||||
<div class="row g-3 mb-3">
|
|
||||||
<div class="col-8"><label class="form-label" for="token2022AmountInput">Montant brut</label><input class="form-control" id="token2022AmountInput" type="text" value="1" /></div>
|
|
||||||
<div class="col-4"><label class="form-label" for="token2022DecimalsInput">Décimales</label><input class="form-control" id="token2022DecimalsInput" max="255" min="0" type="number" value="9" /></div>
|
|
||||||
</div>
|
|
||||||
<div class="d-grid gap-2 d-md-flex">
|
|
||||||
<button class="btn btn-outline-primary flex-fill" id="simulateToken2022Button" type="button">Préflight et simuler</button>
|
|
||||||
<button class="btn btn-danger flex-fill" id="submitToken2022Button" type="button">Confirmer et envoyer</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="accordion-item">
|
|
||||||
<h2 class="accordion-header" id="splElgamalRegistryDecoderHeading"><button aria-controls="splElgamalRegistryDecoderCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#splElgamalRegistryDecoderCollapse" data-bs-toggle="collapse" type="button"><span class="d-flex flex-wrap align-items-center justify-content-between gap-2 w-100 me-2"><span>Décodeur spl_elgamal_registry — ElGamal Registry</span><span class="badge text-bg-primary">Plan exact</span></span></button></h2>
|
|
||||||
<div aria-labelledby="splElgamalRegistryDecoderHeading" class="accordion-collapse collapse" data-bs-parent="#decoderExecutionAccordion" id="splElgamalRegistryDecoderCollapse">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<div class="alert alert-info">Première démo : dériver le Registry PDA et construire le plan exact avec un Proof Context State existant.</div>
|
|
||||||
<div class="mb-3"><label class="form-label" for="elgamalFeePayerInput">Fee payer</label><input class="form-control font-monospace" id="elgamalFeePayerInput" type="text" /></div>
|
|
||||||
<div class="mb-3"><label class="form-label" for="elgamalOwnerInput">Owner du registre</label><input class="form-control font-monospace" id="elgamalOwnerInput" type="text" /></div>
|
|
||||||
<div class="mb-3"><label class="form-label" for="elgamalOperationSelect">Opération</label><select class="form-select" id="elgamalOperationSelect">
|
|
||||||
<option value="create_registry">CreateRegistry</option>
|
|
||||||
<option value="update_registry">UpdateRegistry</option>
|
|
||||||
</select></div>
|
|
||||||
<div class="mb-3"><label class="form-label" for="elgamalProofContextInput">Proof Context State account</label><input class="form-control font-monospace" id="elgamalProofContextInput" type="text" /></div><button class="btn btn-outline-primary w-100" id="buildElgamalRegistryPlanButton" type="button">Construire le plan Registry</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="alert alert-secondary mt-4 mb-0">
|
|
||||||
<strong>Scénarios avec preuve.</strong> CreateRegistry, UpdateRegistry et ConfigureAccountWithRegistry restent dans le panneau ElGamal/Confidential et exigent un Proof Context State valide. Ils ne sont pas présentés comme des scénarios publics exécutables.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-xl-7" id="splExecutionResults">
|
|
||||||
<div class="d-flex align-items-center justify-content-between mb-2">
|
|
||||||
<h2 class="h5 mb-0">Résultats détaillés</h2><small class="text-body-secondary">Plan, simulation, confirmation et journaux métier</small>
|
|
||||||
</div>
|
|
||||||
<div class="accordion mt-4" id="executionDetailsAccordion">
|
|
||||||
<div class="accordion-item">
|
|
||||||
<h2 class="accordion-header">
|
|
||||||
<button class="accordion-button collapsed" data-bs-target="#executionPlanCollapse" data-bs-toggle="collapse" type="button">Plan exact</button>
|
|
||||||
</h2>
|
|
||||||
<div class="accordion-collapse collapse" data-bs-parent="#executionDetailsAccordion" id="executionPlanCollapse">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<textarea class="form-control font-monospace" id="executionPlanOutput" readonly="" rows="16" data-json-viewer="true">Aucun plan.</textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="accordion-item">
|
|
||||||
<h2 class="accordion-header">
|
|
||||||
<button class="accordion-button collapsed" data-bs-target="#executionSimulationCollapse" data-bs-toggle="collapse" type="button">Simulation exacte</button>
|
|
||||||
</h2>
|
|
||||||
<div class="accordion-collapse collapse" data-bs-parent="#executionDetailsAccordion" id="executionSimulationCollapse">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<textarea class="form-control font-monospace" id="executionSimulationOutput" readonly="" rows="16" data-json-viewer="true">Aucune simulation.</textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="accordion-item">
|
|
||||||
<h2 class="accordion-header">
|
|
||||||
<button class="accordion-button collapsed" data-bs-target="#executionDiagnosticsCollapse" data-bs-toggle="collapse" type="button">Confirmation et replay</button>
|
|
||||||
</h2>
|
|
||||||
<div class="accordion-collapse collapse" data-bs-parent="#executionDetailsAccordion" id="executionDiagnosticsCollapse">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<textarea class="form-control font-monospace" id="executionDiagnosticsOutput" readonly="" rows="16" data-json-viewer="true">Aucun diagnostic.</textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="accordion shadow-sm mt-4" id="splBusinessJournalsAccordion">
|
|
||||||
<div class="accordion-item">
|
|
||||||
<h2 class="accordion-header" id="splTokenJournalHeading"><button aria-controls="splTokenJournalCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#splTokenJournalCollapse" data-bs-toggle="collapse" type="button">Journal métier SPL Token</button></h2>
|
|
||||||
<div aria-labelledby="splTokenJournalHeading" class="accordion-collapse collapse" data-bs-parent="#splBusinessJournalsAccordion" id="splTokenJournalCollapse">
|
|
||||||
<div class="accordion-body p-0" id="splTokenJournalHost">
|
|
||||||
<div class="card border-0 rounded-0">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="d-flex flex-wrap align-items-center justify-content-between gap-2 mb-3">
|
|
||||||
<div>
|
|
||||||
<h2 class="h5 mb-0">Journal métier SPL Token</h2>
|
|
||||||
<div class="form-text">Événements commités uniquement, sans solde final reconstruit ni OHLC.</div>
|
|
||||||
</div>
|
|
||||||
<button class="btn btn-sm btn-outline-primary" id="refreshTokenJournalButton" type="button">Actualiser</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="row g-2 mb-3">
|
<div class="mb-3">
|
||||||
<div class="col-12 col-lg-6">
|
<label class="form-label" for="executionRecipientInput">Destinataire</label>
|
||||||
<label class="form-label" for="tokenJournalSignatureInput">Signature contient</label>
|
<div class="input-group">
|
||||||
<input class="form-control font-monospace" id="tokenJournalSignatureInput" type="text" />
|
<input autocomplete="off" class="form-control font-monospace" id="executionRecipientInput" type="text" />
|
||||||
|
<button class="btn btn-outline-secondary" id="generateRecipientButton" type="button">Générer</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-lg-6">
|
<div class="form-text">Une adresse générée ici est jetable : sa clé privée n’est ni conservée ni exposée.</div>
|
||||||
<label class="form-label" for="tokenJournalMintInput">Mint exact</label>
|
</div>
|
||||||
<input class="form-control font-monospace" id="tokenJournalMintInput" type="text" />
|
<div class="row g-3">
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<label class="form-label" for="executionLamportsInput">Lamports transférés</label>
|
||||||
|
<input class="form-control" id="executionLamportsInput" min="1" step="1" type="number" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-lg-6">
|
<div class="col-12 col-md-6">
|
||||||
<label class="form-label" for="tokenJournalAccountInput">Compte exact</label>
|
<label class="form-label" for="executionAirdropInput">Airdrop maximal</label>
|
||||||
<input class="form-control font-monospace" id="tokenJournalAccountInput" type="text" />
|
<input class="form-control" id="executionAirdropInput" min="0" step="1" type="number" value="0" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 col-lg-3">
|
</div>
|
||||||
<label class="form-label" for="tokenJournalFamilySelect">Famille</label>
|
<hr />
|
||||||
<select class="form-select" id="tokenJournalFamilySelect">
|
<div class="form-check form-switch mb-2">
|
||||||
<option value="">Toutes</option>
|
<input class="form-check-input" id="executionOperatorConfirmedInput" type="checkbox" />
|
||||||
<option value="token_account">token_account</option>
|
<label class="form-check-label" for="executionOperatorConfirmedInput">Confirmation opérateur explicite</label>
|
||||||
<option value="admin">admin</option>
|
</div>
|
||||||
<option value="risk">risk</option>
|
<div class="form-check form-switch mb-2">
|
||||||
|
<input class="form-check-input" id="executionForceReplayInput" type="checkbox" />
|
||||||
|
<label class="form-check-label" for="executionForceReplayInput">Forcer le replay post-exécution</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check form-switch mb-3">
|
||||||
|
<input class="form-check-input" id="executionMaterializeInput" type="checkbox" />
|
||||||
|
<label class="form-check-label" for="executionMaterializeInput">Matérialiser après décodage</label>
|
||||||
|
</div>
|
||||||
|
<div class="d-grid gap-2 d-md-flex">
|
||||||
|
<button class="btn btn-outline-primary flex-fill" id="simulateExecutionButton" type="button">Simuler uniquement</button>
|
||||||
|
<button class="btn btn-danger flex-fill" id="submitExecutionButton" type="button">Signer et envoyer</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-items-center justify-content-between mt-4 mb-2">
|
||||||
|
<h2 class="h5 mb-0">Exécutions par décodeur</h2><small class="text-body-secondary">Ouvrir une seule famille à la fois</small>
|
||||||
|
</div>
|
||||||
|
<div class="accordion shadow-sm mt-4" id="decoderExecutionAccordion">
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="splMemoDecoderHeading"><button aria-controls="splMemoDecoderCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#splMemoDecoderCollapse" data-bs-toggle="collapse" type="button"><span class="d-flex flex-wrap align-items-center justify-content-between gap-2 w-100 me-2"><span>Décodeur spl_memo — Memo v4</span><span class="badge text-bg-primary">Exécutable</span></span></button></h2>
|
||||||
|
<div aria-labelledby="splMemoDecoderHeading" class="accordion-collapse collapse" data-bs-parent="#decoderExecutionAccordion" id="splMemoDecoderCollapse">
|
||||||
|
<div class="accordion-body">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="memoMessageInput">Annotation UTF-8 exacte</label>
|
||||||
|
<textarea class="form-control" id="memoMessageInput" maxlength="566" rows="5">khadhroony-bot2 Memo v4 validation</textarea>
|
||||||
|
<div class="form-text">566 octets UTF-8 maximum. La matérialisation `transaction_annotation` et le second replay d’idempotence sont obligatoires après envoi.</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-check form-switch mb-3">
|
||||||
|
<input checked="" class="form-check-input" id="memoWalletSignerInput" type="checkbox" />
|
||||||
|
<label class="form-check-label" for="memoWalletSignerInput">Inclure le wallet comme signer Memo readonly</label>
|
||||||
|
</div>
|
||||||
|
<div class="alert alert-secondary py-2 small" role="note">
|
||||||
|
Ce parcours réutilise le profil, la confirmation opérateur et l’option de force replay du panneau System ci-dessus. Aucune clé privée ne traverse la WebView.
|
||||||
|
</div>
|
||||||
|
<div class="d-grid gap-2 d-md-flex">
|
||||||
|
<button class="btn btn-outline-info flex-fill" id="simulateMemoButton" type="button">Simuler Memo</button>
|
||||||
|
<button class="btn btn-danger flex-fill" id="submitMemoButton" type="button">Signer et envoyer Memo</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="splTokenDecoderHeading"><button aria-controls="splTokenDecoderCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#splTokenDecoderCollapse" data-bs-toggle="collapse" type="button"><span class="d-flex flex-wrap align-items-center justify-content-between gap-2 w-100 me-2"><span>Décodeur spl_token — TransferChecked</span><span class="badge text-bg-primary">Exécutable</span></span></button></h2>
|
||||||
|
<div aria-labelledby="splTokenDecoderHeading" class="accordion-collapse collapse" data-bs-parent="#decoderExecutionAccordion" id="splTokenDecoderCollapse">
|
||||||
|
<div class="accordion-body">
|
||||||
|
<div class="alert alert-secondary py-2 small" role="note">
|
||||||
|
Le mint et les decimals sont explicites. Le préflight vérifie les deux comptes, le solde et l’autorité avant toute simulation. L’envoi réutilise le profil et la confirmation opérateur communs.
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="tokenSourceInput">Compte source</label>
|
||||||
|
<input autocomplete="off" class="form-control font-monospace" id="tokenSourceInput" type="text" />
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="tokenMintInput">Mint</label>
|
||||||
|
<input autocomplete="off" class="form-control font-monospace" id="tokenMintInput" type="text" />
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="tokenDestinationInput">Compte destination</label>
|
||||||
|
<input autocomplete="off" class="form-control font-monospace" id="tokenDestinationInput" type="text" />
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="tokenAuthorityInput">Autorité simple</label>
|
||||||
|
<input autocomplete="off" class="form-control font-monospace" id="tokenAuthorityInput" type="text" />
|
||||||
|
<div class="form-text">Doit correspondre au wallet persistant du profil pour un envoi.</div>
|
||||||
|
</div>
|
||||||
|
<div class="row g-3 mb-3">
|
||||||
|
<div class="col-12 col-md-7">
|
||||||
|
<label class="form-label" for="tokenAmountRawInput">Montant brut exact</label>
|
||||||
|
<input class="form-control font-monospace" id="tokenAmountRawInput" inputmode="numeric" type="text" value="1" />
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-5">
|
||||||
|
<label class="form-label" for="tokenDecimalsInput">Decimals</label>
|
||||||
|
<input class="form-control" id="tokenDecimalsInput" max="255" min="0" step="1" type="number" value="9" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-grid gap-2 d-md-flex">
|
||||||
|
<button class="btn btn-outline-primary flex-fill" id="simulateTokenButton" type="button">Préflight et simuler</button>
|
||||||
|
<button class="btn btn-danger flex-fill" id="submitTokenButton" type="button">Signer et envoyer Token</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="splAtaDecoderHeading"><button aria-controls="splAtaDecoderCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#splAtaDecoderCollapse" data-bs-toggle="collapse" type="button"><span class="d-flex flex-wrap align-items-center justify-content-between gap-2 w-100 me-2"><span>Décodeur spl_associated_token_account — Create / CreateIdempotent</span><span class="badge text-bg-primary">Exécutable</span></span></button></h2>
|
||||||
|
<div aria-labelledby="splAtaDecoderHeading" class="accordion-collapse collapse" data-bs-parent="#decoderExecutionAccordion" id="splAtaDecoderCollapse">
|
||||||
|
<div class="accordion-body">
|
||||||
|
<div class="row g-3 mb-3">
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<label class="form-label" for="ataTokenProgramSelect">Token Program cible</label>
|
||||||
|
<select class="form-select" id="ataTokenProgramSelect">
|
||||||
|
<option value="classic">SPL Token classique</option>
|
||||||
|
<option value="token2022">Token-2022</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 col-lg-3">
|
<div class="col-12 col-md-6">
|
||||||
<label class="form-label" for="tokenJournalLimitInput">Limite</label>
|
<label class="form-label" for="ataModeSelect">Mode</label>
|
||||||
<input class="form-control" id="tokenJournalLimitInput" max="500" min="1" step="1" type="number" value="100" />
|
<select class="form-select" id="ataModeSelect">
|
||||||
</div>
|
<option value="create_idempotent">CreateIdempotent</option>
|
||||||
<div class="col-12">
|
<option value="create">Create</option>
|
||||||
<label class="form-label" for="tokenJournalOperationInput">Opération exacte</label>
|
</select>
|
||||||
<input class="form-control font-monospace" id="tokenJournalOperationInput" placeholder="transfer_checked" type="text" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-responsive">
|
<div class="mb-3">
|
||||||
<table class="table table-sm table-hover align-middle">
|
<label class="form-label" for="ataMintInput">Mint</label>
|
||||||
<thead>
|
<input autocomplete="off" class="form-control font-monospace" id="ataMintInput" type="text" />
|
||||||
<tr>
|
|
||||||
<th>Slot</th>
|
|
||||||
<th>Opération</th>
|
|
||||||
<th>Famille</th>
|
|
||||||
<th>Montant brut</th>
|
|
||||||
<th>Signature</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="tokenJournalRows">
|
|
||||||
<tr>
|
|
||||||
<td class="text-body-secondary" colspan="5">Aucune lecture.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
<label class="form-label" for="tokenJournalDetailOutput">Détail JSON de la ligne sélectionnée</label>
|
<div class="mb-3">
|
||||||
<textarea class="form-control font-monospace" id="tokenJournalDetailOutput" readonly="" rows="14">Aucun événement sélectionné.</textarea>
|
<label class="form-label" for="ataPayerInput">Payer readonly</label>
|
||||||
|
<input class="form-control font-monospace" id="ataPayerInput" readonly="" type="text" />
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="ataWalletOwnerInput">Wallet owner readonly</label>
|
||||||
|
<input class="form-control font-monospace" id="ataWalletOwnerInput" readonly="" type="text" />
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="ataDerivedInput">ATA dérivé readonly</label>
|
||||||
|
<input class="form-control font-monospace" id="ataDerivedInput" readonly="" type="text" />
|
||||||
|
<div class="form-text">Actualisé depuis le backend avec les seeds wallet, Token Program et mint.</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-grid gap-2 d-md-flex">
|
||||||
|
<button class="btn btn-outline-secondary flex-fill" id="deriveAtaButton" type="button">Dériver</button>
|
||||||
|
<button class="btn btn-outline-primary flex-fill" id="simulateAtaButton" type="button">Préflight et simuler</button>
|
||||||
|
<button class="btn btn-danger flex-fill" id="submitAtaButton" type="button">Confirmer et envoyer</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="splToken2022DecoderHeading"><button aria-controls="splToken2022DecoderCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#splToken2022DecoderCollapse" data-bs-toggle="collapse" type="button"><span class="d-flex flex-wrap align-items-center justify-content-between gap-2 w-100 me-2"><span>Exécution spl_token2022 — scénarios publics</span><span class="badge text-bg-success">Exécutable</span></span></button></h2>
|
||||||
|
<div aria-labelledby="splToken2022DecoderHeading" class="accordion-collapse collapse" data-bs-parent="#decoderExecutionAccordion" id="splToken2022DecoderCollapse">
|
||||||
|
<div class="accordion-body">
|
||||||
|
<div class="alert alert-info">Chaque opération est simulée sur le message exact avant toute signature. Les scénarios sont indépendants et réutilisent la fixture chargée dans les deux terminaux.</div>
|
||||||
|
<div class="d-grid mb-3"><button class="btn btn-outline-secondary" id="loadToken2022FixtureButton" type="button">Charger la fixture Token-2022</button></div>
|
||||||
|
<div class="form-text mb-3" id="token2022FixtureHelp">Aucune fixture chargée.</div>
|
||||||
|
<div class="mb-3"><label class="form-label" for="token2022ScenarioSelect">Scénario</label><select class="form-select" id="token2022ScenarioSelect">
|
||||||
|
<option value="token2022_mint_to_checked">MintToChecked</option>
|
||||||
|
<option value="token2022_transfer_checked">TransferChecked</option>
|
||||||
|
<option value="token2022_approve_checked">ApproveChecked</option>
|
||||||
|
<option value="token2022_revoke">Revoke</option>
|
||||||
|
<option value="token2022_burn_checked">BurnChecked</option>
|
||||||
|
<option value="token2022_freeze_account">FreezeAccount</option>
|
||||||
|
<option value="token2022_thaw_account">ThawAccount</option>
|
||||||
|
<option value="token2022_close_destination">CloseAccount</option>
|
||||||
|
</select></div>
|
||||||
|
<div class="mb-3"><label class="form-label" for="token2022SourceInput">Compte source / compte cible</label><input class="form-control font-monospace" id="token2022SourceInput" type="text" /></div>
|
||||||
|
<div class="mb-3"><label class="form-label" for="token2022MintInput">Mint Token-2022</label><input class="form-control font-monospace" id="token2022MintInput" type="text" /></div>
|
||||||
|
<div class="mb-3"><label class="form-label" for="token2022DestinationInput">Compte destination / destination lamports</label><input class="form-control font-monospace" id="token2022DestinationInput" type="text" /></div>
|
||||||
|
<div class="mb-3"><label class="form-label" for="token2022DelegateInput">Delegate</label><input class="form-control font-monospace" id="token2022DelegateInput" type="text" /></div>
|
||||||
|
<div class="mb-3"><label class="form-label" for="token2022AuthorityInput">Autorité</label><input class="form-control font-monospace" id="token2022AuthorityInput" type="text" /></div>
|
||||||
|
<div class="mb-3"><label class="form-label" for="token2022FreezeAuthorityInput">Freeze authority</label><input class="form-control font-monospace" id="token2022FreezeAuthorityInput" type="text" /></div>
|
||||||
|
<div class="row g-3 mb-3">
|
||||||
|
<div class="col-8"><label class="form-label" for="token2022AmountInput">Montant brut</label><input class="form-control" id="token2022AmountInput" type="text" value="1" /></div>
|
||||||
|
<div class="col-4"><label class="form-label" for="token2022DecimalsInput">Décimales</label><input class="form-control" id="token2022DecimalsInput" max="255" min="0" type="number" value="9" /></div>
|
||||||
|
</div>
|
||||||
|
<div class="d-grid gap-2 d-md-flex">
|
||||||
|
<button class="btn btn-outline-primary flex-fill" id="simulateToken2022Button" type="button">Préflight et simuler</button>
|
||||||
|
<button class="btn btn-danger flex-fill" id="submitToken2022Button" type="button">Confirmer et envoyer</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="splElgamalRegistryDecoderHeading"><button aria-controls="splElgamalRegistryDecoderCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#splElgamalRegistryDecoderCollapse" data-bs-toggle="collapse" type="button"><span class="d-flex flex-wrap align-items-center justify-content-between gap-2 w-100 me-2"><span>Décodeur spl_elgamal_registry — ElGamal Registry</span><span class="badge text-bg-primary">Plan exact</span></span></button></h2>
|
||||||
|
<div aria-labelledby="splElgamalRegistryDecoderHeading" class="accordion-collapse collapse" data-bs-parent="#decoderExecutionAccordion" id="splElgamalRegistryDecoderCollapse">
|
||||||
|
<div class="accordion-body">
|
||||||
|
<div class="alert alert-info">Première démo : dériver le Registry PDA et construire le plan exact avec un Proof Context State existant.</div>
|
||||||
|
<div class="mb-3"><label class="form-label" for="elgamalFeePayerInput">Fee payer</label><input class="form-control font-monospace" id="elgamalFeePayerInput" type="text" /></div>
|
||||||
|
<div class="mb-3"><label class="form-label" for="elgamalOwnerInput">Owner du registre</label><input class="form-control font-monospace" id="elgamalOwnerInput" type="text" /></div>
|
||||||
|
<div class="mb-3"><label class="form-label" for="elgamalOperationSelect">Opération</label><select class="form-select" id="elgamalOperationSelect">
|
||||||
|
<option value="create_registry">CreateRegistry</option>
|
||||||
|
<option value="update_registry">UpdateRegistry</option>
|
||||||
|
</select></div>
|
||||||
|
<div class="mb-3"><label class="form-label" for="elgamalProofContextInput">Proof Context State account</label><input class="form-control font-monospace" id="elgamalProofContextInput" type="text" /></div><button class="btn btn-outline-primary w-100" id="buildElgamalRegistryPlanButton" type="button">Construire le plan Registry</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="alert alert-secondary mt-4 mb-0">
|
||||||
|
<strong>Scénarios avec preuve.</strong> CreateRegistry, UpdateRegistry et ConfigureAccountWithRegistry restent dans le panneau ElGamal/Confidential et exigent un Proof Context State valide. Ils ne sont pas présentés comme des scénarios publics exécutables.
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="accordion-item">
|
<div class="col-12 col-xl-7" id="splExecutionResults">
|
||||||
<h2 class="accordion-header" id="ataLifecycleJournalHeading"><button aria-controls="ataLifecycleJournalCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#ataLifecycleJournalCollapse" data-bs-toggle="collapse" type="button">Journal lifecycle ATA</button></h2>
|
<div class="d-flex align-items-center justify-content-between mb-2">
|
||||||
<div aria-labelledby="ataLifecycleJournalHeading" class="accordion-collapse collapse" data-bs-parent="#splBusinessJournalsAccordion" id="ataLifecycleJournalCollapse">
|
<h2 class="h5 mb-0">Résultats détaillés</h2><small class="text-body-secondary">Plan, simulation, confirmation et journaux métier</small>
|
||||||
<div class="accordion-body p-0" id="ataLifecycleJournalHost">
|
</div>
|
||||||
<div class="card border-0 rounded-0">
|
<div class="accordion mt-4" id="executionDetailsAccordion">
|
||||||
<div class="card-body">
|
<div class="accordion-item">
|
||||||
<div class="d-flex flex-wrap align-items-center justify-content-between gap-2 mb-3">
|
<h2 class="accordion-header">
|
||||||
<div>
|
<button class="accordion-button collapsed" data-bs-target="#executionPlanCollapse" data-bs-toggle="collapse" type="button">Plan exact</button>
|
||||||
<h2 class="h5 mb-0">Journal lifecycle ATA</h2>
|
</h2>
|
||||||
<div class="form-text">Création, réutilisation idempotente et récupération nested, sans duplication des CPI Token.</div>
|
<div class="accordion-collapse collapse" data-bs-parent="#executionDetailsAccordion" id="executionPlanCollapse">
|
||||||
</div>
|
<div class="accordion-body">
|
||||||
<button class="btn btn-sm btn-outline-primary" id="refreshAtaJournalButton" type="button">Actualiser</button>
|
<textarea class="form-control font-monospace" data-json-viewer="true" id="executionPlanOutput" readonly="" rows="16">Aucun plan.</textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="row g-2 mb-3">
|
</div>
|
||||||
<div class="col-12 col-lg-6">
|
</div>
|
||||||
<label class="form-label" for="ataJournalSignatureInput">Signature contient</label>
|
<div class="accordion-item">
|
||||||
<input class="form-control font-monospace" id="ataJournalSignatureInput" type="text" />
|
<h2 class="accordion-header">
|
||||||
</div>
|
<button class="accordion-button collapsed" data-bs-target="#executionSimulationCollapse" data-bs-toggle="collapse" type="button">Simulation exacte</button>
|
||||||
<div class="col-12 col-lg-6">
|
</h2>
|
||||||
<label class="form-label" for="ataJournalMintInput">Mint exact</label>
|
<div class="accordion-collapse collapse" data-bs-parent="#executionDetailsAccordion" id="executionSimulationCollapse">
|
||||||
<input class="form-control font-monospace" id="ataJournalMintInput" type="text" />
|
<div class="accordion-body">
|
||||||
</div>
|
<textarea class="form-control font-monospace" data-json-viewer="true" id="executionSimulationOutput" readonly="" rows="16">Aucune simulation.</textarea>
|
||||||
<div class="col-12 col-lg-6">
|
</div>
|
||||||
<label class="form-label" for="ataJournalAddressInput">ATA exact</label>
|
</div>
|
||||||
<input class="form-control font-monospace" id="ataJournalAddressInput" type="text" />
|
</div>
|
||||||
</div>
|
<div class="accordion-item">
|
||||||
<div class="col-8 col-lg-4">
|
<h2 class="accordion-header">
|
||||||
<label class="form-label" for="ataJournalOperationInput">Opération</label>
|
<button class="accordion-button collapsed" data-bs-target="#executionDiagnosticsCollapse" data-bs-toggle="collapse" type="button">Confirmation et replay</button>
|
||||||
<input class="form-control font-monospace" id="ataJournalOperationInput" type="text" />
|
</h2>
|
||||||
</div>
|
<div class="accordion-collapse collapse" data-bs-parent="#executionDetailsAccordion" id="executionDiagnosticsCollapse">
|
||||||
<div class="col-4 col-lg-2">
|
<div class="accordion-body">
|
||||||
<label class="form-label" for="ataJournalLimitInput">Limite</label>
|
<textarea class="form-control font-monospace" data-json-viewer="true" id="executionDiagnosticsOutput" readonly="" rows="16">Aucun diagnostic.</textarea>
|
||||||
<input class="form-control" id="ataJournalLimitInput" max="500" min="1" type="number" value="100" />
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="accordion shadow-sm mt-4" id="splBusinessJournalsAccordion">
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="splTokenJournalHeading"><button aria-controls="splTokenJournalCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#splTokenJournalCollapse" data-bs-toggle="collapse" type="button">Journal métier SPL Token</button></h2>
|
||||||
|
<div aria-labelledby="splTokenJournalHeading" class="accordion-collapse collapse" data-bs-parent="#splBusinessJournalsAccordion" id="splTokenJournalCollapse">
|
||||||
|
<div class="accordion-body p-0" id="splTokenJournalHost">
|
||||||
|
<div class="card border-0 rounded-0">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex flex-wrap align-items-center justify-content-between gap-2 mb-3">
|
||||||
|
<div>
|
||||||
|
<h2 class="h5 mb-0">Journal métier SPL Token</h2>
|
||||||
|
<div class="form-text">Événements commités uniquement, sans solde final reconstruit ni OHLC.</div>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-sm btn-outline-primary" id="refreshTokenJournalButton" type="button">Actualiser</button>
|
||||||
|
</div>
|
||||||
|
<div class="row g-2 mb-3">
|
||||||
|
<div class="col-12 col-lg-6">
|
||||||
|
<label class="form-label" for="tokenJournalSignatureInput">Signature contient</label>
|
||||||
|
<input class="form-control font-monospace" id="tokenJournalSignatureInput" type="text" />
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-lg-6">
|
||||||
|
<label class="form-label" for="tokenJournalMintInput">Mint exact</label>
|
||||||
|
<input class="form-control font-monospace" id="tokenJournalMintInput" type="text" />
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-lg-6">
|
||||||
|
<label class="form-label" for="tokenJournalAccountInput">Compte exact</label>
|
||||||
|
<input class="form-control font-monospace" id="tokenJournalAccountInput" type="text" />
|
||||||
|
</div>
|
||||||
|
<div class="col-6 col-lg-3">
|
||||||
|
<label class="form-label" for="tokenJournalFamilySelect">Famille</label>
|
||||||
|
<select class="form-select" id="tokenJournalFamilySelect">
|
||||||
|
<option value="">Toutes</option>
|
||||||
|
<option value="token_account">token_account</option>
|
||||||
|
<option value="admin">admin</option>
|
||||||
|
<option value="risk">risk</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-6 col-lg-3">
|
||||||
|
<label class="form-label" for="tokenJournalLimitInput">Limite</label>
|
||||||
|
<input class="form-control" id="tokenJournalLimitInput" max="500" min="1" step="1" type="number" value="100" />
|
||||||
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<label class="form-label" for="tokenJournalOperationInput">Opération exacte</label>
|
||||||
|
<input class="form-control font-monospace" id="tokenJournalOperationInput" placeholder="transfer_checked" type="text" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-sm table-hover align-middle">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Slot</th>
|
||||||
|
<th>Opération</th>
|
||||||
|
<th>Famille</th>
|
||||||
|
<th>Montant brut</th>
|
||||||
|
<th>Signature</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="tokenJournalRows">
|
||||||
|
<tr>
|
||||||
|
<td class="text-body-secondary" colspan="5">Aucune lecture.</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<label class="form-label" for="tokenJournalDetailOutput">Détail JSON de la ligne sélectionnée</label>
|
||||||
|
<textarea class="form-control font-monospace" id="tokenJournalDetailOutput" readonly="" rows="14">Aucun événement sélectionné.</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="ataLifecycleJournalHeading"><button aria-controls="ataLifecycleJournalCollapse" aria-expanded="false" class="accordion-button collapsed" data-bs-target="#ataLifecycleJournalCollapse" data-bs-toggle="collapse" type="button">Journal lifecycle ATA</button></h2>
|
||||||
|
<div aria-labelledby="ataLifecycleJournalHeading" class="accordion-collapse collapse" data-bs-parent="#splBusinessJournalsAccordion" id="ataLifecycleJournalCollapse">
|
||||||
|
<div class="accordion-body p-0" id="ataLifecycleJournalHost">
|
||||||
|
<div class="card border-0 rounded-0">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex flex-wrap align-items-center justify-content-between gap-2 mb-3">
|
||||||
|
<div>
|
||||||
|
<h2 class="h5 mb-0">Journal lifecycle ATA</h2>
|
||||||
|
<div class="form-text">Création, réutilisation idempotente et récupération nested, sans duplication des CPI Token.</div>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-sm btn-outline-primary" id="refreshAtaJournalButton" type="button">Actualiser</button>
|
||||||
|
</div>
|
||||||
|
<div class="row g-2 mb-3">
|
||||||
|
<div class="col-12 col-lg-6">
|
||||||
|
<label class="form-label" for="ataJournalSignatureInput">Signature contient</label>
|
||||||
|
<input class="form-control font-monospace" id="ataJournalSignatureInput" type="text" />
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-lg-6">
|
||||||
|
<label class="form-label" for="ataJournalMintInput">Mint exact</label>
|
||||||
|
<input class="form-control font-monospace" id="ataJournalMintInput" type="text" />
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-lg-6">
|
||||||
|
<label class="form-label" for="ataJournalAddressInput">ATA exact</label>
|
||||||
|
<input class="form-control font-monospace" id="ataJournalAddressInput" type="text" />
|
||||||
|
</div>
|
||||||
|
<div class="col-8 col-lg-4">
|
||||||
|
<label class="form-label" for="ataJournalOperationInput">Opération</label>
|
||||||
|
<input class="form-control font-monospace" id="ataJournalOperationInput" type="text" />
|
||||||
|
</div>
|
||||||
|
<div class="col-4 col-lg-2">
|
||||||
|
<label class="form-label" for="ataJournalLimitInput">Limite</label>
|
||||||
|
<input class="form-control" id="ataJournalLimitInput" max="500" min="1" type="number" value="100" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<textarea class="form-control font-monospace" id="ataJournalOutput" readonly="" rows="14">Aucune lecture.</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<textarea class="form-control font-monospace" id="ataJournalOutput" readonly="" rows="14">Aucune lecture.</textarea>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="card shadow-sm border-0 mt-4">
|
||||||
</div>
|
<div class="card-body">
|
||||||
<div class="card shadow-sm border-0 mt-4">
|
<h2 class="h5 mb-3">Résumé</h2>
|
||||||
<div class="card-body">
|
<textarea class="form-control font-monospace" data-json-viewer="true" id="executionSummaryOutput" readonly="" rows="14">Aucun résultat.</textarea>
|
||||||
<h2 class="h5 mb-3">Résumé</h2>
|
</div>
|
||||||
<textarea class="form-control font-monospace" id="executionSummaryOutput" readonly="" rows="14" data-json-viewer="true">Aucun résultat.</textarea>
|
</div>
|
||||||
</div>
|
<div class="card shadow-sm border-0 mt-4">
|
||||||
</div>
|
<div class="card-body">
|
||||||
<div class="card shadow-sm border-0 mt-4">
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||||
<div class="card-body">
|
<h2 class="h5 mb-0">Journal</h2>
|
||||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
|
||||||
<h2 class="h5 mb-0">Journal</h2>
|
</div>
|
||||||
<button class="btn btn-sm btn-outline-secondary" id="clearExecutionLogButton" type="button">Effacer</button>
|
<textarea class="form-control font-monospace" id="executionLogOutput" readonly="" rows="18"></textarea>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<textarea class="form-control font-monospace" id="executionLogOutput" readonly="" rows="18"></textarea>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<footer class="app-footer bg-dark text-light">
|
<footer class="app-footer bg-dark text-light">
|
||||||
<div class="container h-100 d-flex align-items-center">
|
<div class="container h-100 d-flex align-items-center">
|
||||||
<div class="row flex-grow-1 align-items-center">
|
<div class="row flex-grow-1 align-items-center">
|
||||||
<div class="col-12 text-center text-small my-1 my-md-0">© 2026 SASEDEV</div>
|
<div class="col-12 text-center text-small my-1 my-md-0">© 2026 SASEDEV</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
<script defer="" src="ts/demo_execution_spl.ts" type="module"></script>
|
<script defer="" src="ts/demo_execution_spl.ts" type="module"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -1,22 +1,23 @@
|
|||||||
<!-- file: kb-app-demo-desktop/frontend/demo_http.html -->
|
<!-- file: kb-app-demo-desktop/frontend/demo_http.html -->
|
||||||
<!-- version: 3 -->
|
<!-- version: 4 -->
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||||
<title>Khadhroony Bot3 - HTTP JSON-RPC</title>
|
<link rel="icon" href="imgs/favicon.png">
|
||||||
<link rel="stylesheet" href="sass/main.scss" />
|
<link rel="stylesheet" href="sass/main.scss">
|
||||||
|
<title>Khadhroony Bot3 — HTTP JSON-RPC</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="bg-body-tertiary">
|
<body>
|
||||||
<header class="app-header">
|
<header class="app-header">
|
||||||
<nav class="navbar navbar-expand-lg h-100 py-0 bg-light text-dark">
|
<nav class="navbar navbar-expand-lg h-100 py-0 bg-light text-dark">
|
||||||
<div class="container my-0">
|
<div class="container-fluid px-4 my-0">
|
||||||
<div class="navbar-brand d-flex align-items-center">
|
<div class="navbar-brand d-flex align-items-center">
|
||||||
<img alt="Logo" src="imgs/logo.png" class="app-logo" />
|
<img alt="Logo" src="imgs/logo.png" class="app-logo">
|
||||||
<span class="ps-2 fs-4 fw-bold text-primary font-logo">HTTP JSON-RPC</span>
|
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3 — <span class="badge text-bg-primary">HTTP JSON-RPC</span></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
@@ -24,9 +25,9 @@
|
|||||||
|
|
||||||
<main class="app-main">
|
<main class="app-main">
|
||||||
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
||||||
<div class="container py-4">
|
<div class="container-fluid px-4 py-4">
|
||||||
<div class="row g-4">
|
<div class="row g-4 justify-content-center">
|
||||||
<div class="col-12 col-xl-5">
|
<div class="col-12">
|
||||||
<div class="card shadow-sm border-0">
|
<div class="card shadow-sm border-0">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h1 class="h4 card-title">Requête HTTP Solana standard</h1>
|
<h1 class="h4 card-title">Requête HTTP Solana standard</h1>
|
||||||
@@ -89,8 +90,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script type="module" src="ts/demo_http.ts" defer></script>
|
<script type="module" src="ts/demo_http.ts" defer></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -1,25 +1,23 @@
|
|||||||
<!-- file: kb_app_demo/frontend/demo_sql_diag.html -->
|
<!-- file: kb_app_demo/frontend/demo_sql_diag.html -->
|
||||||
<!-- version: 2 -->
|
<!-- version: 3 -->
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||||
<title>Khadhroony-Bot3 - SQL diagnostics</title>
|
<link rel="icon" href="imgs/favicon.png">
|
||||||
<link rel="stylesheet" href="sass/main.scss" />
|
<link rel="stylesheet" href="sass/main.scss">
|
||||||
|
<title>Khadhroony Bot3 — SQL diagnostics</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="bg-body-tertiary">
|
<body>
|
||||||
<header class="app-header">
|
<header class="app-header">
|
||||||
<nav class="navbar navbar-expand-lg h-100 py-0 bg-light text-dark">
|
<nav class="navbar navbar-expand-lg h-100 py-0 bg-light text-dark">
|
||||||
<div class="container my-0">
|
<div class="container-fluid px-4 my-0">
|
||||||
<div class="navbar-brand d-flex align-items-center">
|
<div class="navbar-brand d-flex align-items-center">
|
||||||
<img alt="Logo" src="imgs/logo.png" class="app-logo" />
|
<img alt="Logo" src="imgs/logo.png" class="app-logo">
|
||||||
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3</span>
|
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3 — <span class="badge text-bg-primary">SQL diagnostics</span></span>
|
||||||
</div>
|
|
||||||
<div class="ms-auto d-flex align-items-center gap-2">
|
|
||||||
<span class="badge text-bg-primary">SQL diagnostics</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
@@ -27,8 +25,8 @@
|
|||||||
|
|
||||||
<main class="app-main">
|
<main class="app-main">
|
||||||
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
||||||
<div class="container-fluid py-4 px-4">
|
<div class="container-fluid px-4 py-4">
|
||||||
<div class="row g-4">
|
<div class="row g-4 justify-content-center">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="card shadow-sm border-0">
|
<div class="card shadow-sm border-0">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@@ -102,14 +100,11 @@
|
|||||||
<footer class="app-footer bg-dark text-light">
|
<footer class="app-footer bg-dark text-light">
|
||||||
<div class="container h-100 d-flex align-items-center">
|
<div class="container h-100 d-flex align-items-center">
|
||||||
<div class="row flex-grow-1 align-items-center">
|
<div class="row flex-grow-1 align-items-center">
|
||||||
<div class="col-12 text-center text-small my-1 my-md-0">
|
<div class="col-12 text-center text-small my-1 my-md-0">© 2026 SASEDEV</div>
|
||||||
© 2026 SASEDEV
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script type="module" src="ts/demo_sql_diag.ts" defer></script>
|
<script type="module" src="ts/demo_sql_diag.ts" defer></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -1,25 +1,23 @@
|
|||||||
<!-- file: kb_app_demo/frontend/demo_sql_pg_core.html -->
|
<!-- file: kb_app_demo/frontend/demo_sql_pg_core.html -->
|
||||||
<!-- version: 3 -->
|
<!-- version: 4 -->
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||||
<title>Khadhroony-Bot3 - PostgreSQL core store</title>
|
<link rel="icon" href="imgs/favicon.png">
|
||||||
<link rel="stylesheet" href="sass/main.scss" />
|
<link rel="stylesheet" href="sass/main.scss">
|
||||||
|
<title>Khadhroony Bot3 — PostgreSQL core store</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="bg-body-tertiary">
|
<body>
|
||||||
<header class="app-header">
|
<header class="app-header">
|
||||||
<nav class="navbar navbar-expand-lg h-100 py-0 bg-light text-dark">
|
<nav class="navbar navbar-expand-lg h-100 py-0 bg-light text-dark">
|
||||||
<div class="container my-0">
|
<div class="container-fluid px-4 my-0">
|
||||||
<div class="navbar-brand d-flex align-items-center">
|
<div class="navbar-brand d-flex align-items-center">
|
||||||
<img alt="Logo" src="imgs/logo.png" class="app-logo" />
|
<img alt="Logo" src="imgs/logo.png" class="app-logo">
|
||||||
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3</span>
|
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3 — <span class="badge text-bg-primary">PostgreSQL core store</span></span>
|
||||||
</div>
|
|
||||||
<div class="ms-auto d-flex align-items-center gap-2">
|
|
||||||
<span class="badge text-bg-primary">PostgreSQL core</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
@@ -27,8 +25,8 @@
|
|||||||
|
|
||||||
<main class="app-main">
|
<main class="app-main">
|
||||||
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
||||||
<div class="container-fluid py-4 px-4">
|
<div class="container-fluid px-4 py-4">
|
||||||
<div class="row g-4">
|
<div class="row g-4 justify-content-center">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="card shadow-sm border-0">
|
<div class="card shadow-sm border-0">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@@ -89,14 +87,11 @@
|
|||||||
<footer class="app-footer bg-dark text-light">
|
<footer class="app-footer bg-dark text-light">
|
||||||
<div class="container h-100 d-flex align-items-center">
|
<div class="container h-100 d-flex align-items-center">
|
||||||
<div class="row flex-grow-1 align-items-center">
|
<div class="row flex-grow-1 align-items-center">
|
||||||
<div class="col-12 text-center text-small my-1 my-md-0">
|
<div class="col-12 text-center text-small my-1 my-md-0">© 2026 SASEDEV</div>
|
||||||
© 2026 SASEDEV
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script type="module" src="ts/demo_sql_pg_core.ts" defer></script>
|
<script type="module" src="ts/demo_sql_pg_core.ts" defer></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -1,25 +1,23 @@
|
|||||||
<!-- file: kb_app_demo/frontend/demo_sql_pg_raw.html -->
|
<!-- file: kb_app_demo/frontend/demo_sql_pg_raw.html -->
|
||||||
<!-- version: 4 -->
|
<!-- version: 5 -->
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||||
<title>Khadhroony-Bot3 - PostgreSQL canonical acquisition</title>
|
<link rel="icon" href="imgs/favicon.png">
|
||||||
<link rel="stylesheet" href="sass/main.scss" />
|
<link rel="stylesheet" href="sass/main.scss">
|
||||||
|
<title>Khadhroony Bot3 — PostgreSQL canonical acquisition</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="bg-body-tertiary">
|
<body>
|
||||||
<header class="app-header">
|
<header class="app-header">
|
||||||
<nav class="navbar navbar-expand-lg h-100 py-0 bg-light text-dark">
|
<nav class="navbar navbar-expand-lg h-100 py-0 bg-light text-dark">
|
||||||
<div class="container my-0">
|
<div class="container-fluid px-4 my-0">
|
||||||
<div class="navbar-brand d-flex align-items-center">
|
<div class="navbar-brand d-flex align-items-center">
|
||||||
<img alt="Logo" src="imgs/logo.png" class="app-logo" />
|
<img alt="Logo" src="imgs/logo.png" class="app-logo">
|
||||||
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3</span>
|
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3 — <span class="badge text-bg-primary">PostgreSQL canonical acquisition</span></span>
|
||||||
</div>
|
|
||||||
<div class="ms-auto d-flex align-items-center gap-2">
|
|
||||||
<span class="badge text-bg-primary">PostgreSQL acquisition</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
@@ -27,8 +25,8 @@
|
|||||||
|
|
||||||
<main class="app-main">
|
<main class="app-main">
|
||||||
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
||||||
<div class="container-fluid py-4 px-4">
|
<div class="container-fluid px-4 py-4">
|
||||||
<div class="row g-4">
|
<div class="row g-4 justify-content-center">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="card shadow-sm border-0">
|
<div class="card shadow-sm border-0">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@@ -89,14 +87,11 @@
|
|||||||
<footer class="app-footer bg-dark text-light">
|
<footer class="app-footer bg-dark text-light">
|
||||||
<div class="container h-100 d-flex align-items-center">
|
<div class="container h-100 d-flex align-items-center">
|
||||||
<div class="row flex-grow-1 align-items-center">
|
<div class="row flex-grow-1 align-items-center">
|
||||||
<div class="col-12 text-center text-small my-1 my-md-0">
|
<div class="col-12 text-center text-small my-1 my-md-0">© 2026 SASEDEV</div>
|
||||||
© 2026 SASEDEV
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script type="module" src="ts/demo_sql_pg_raw.ts" defer></script>
|
<script type="module" src="ts/demo_sql_pg_raw.ts" defer></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -1,22 +1,23 @@
|
|||||||
<!-- file: kb_app_demo/frontend/demo_sql_replay_candidates.html -->
|
<!-- file: kb_app_demo/frontend/demo_sql_replay_candidates.html -->
|
||||||
<!-- version: 6 -->
|
<!-- version: 7 -->
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||||
<title>Khadhroony Bot3 - Candidats de replay SQL</title>
|
<link rel="icon" href="imgs/favicon.png">
|
||||||
<link rel="stylesheet" href="sass/main.scss" />
|
<link rel="stylesheet" href="sass/main.scss">
|
||||||
|
<title>Khadhroony Bot3 — Candidats de replay SQL</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="bg-body-tertiary">
|
<body>
|
||||||
<header class="app-header">
|
<header class="app-header">
|
||||||
<nav class="navbar navbar-expand-lg h-100 py-0 bg-light text-dark">
|
<nav class="navbar navbar-expand-lg h-100 py-0 bg-light text-dark">
|
||||||
<div class="container-fluid px-4 my-0">
|
<div class="container-fluid px-4 my-0">
|
||||||
<div class="navbar-brand d-flex align-items-center">
|
<div class="navbar-brand d-flex align-items-center">
|
||||||
<img alt="Logo" src="imgs/logo.png" class="app-logo" />
|
<img alt="Logo" src="imgs/logo.png" class="app-logo">
|
||||||
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Candidats de replay SQL</span>
|
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3 — <span class="badge text-bg-primary">SQL replay candidates</span></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-auto d-flex align-items-center gap-2">
|
<div class="ms-auto d-flex align-items-center gap-2">
|
||||||
<span id="replayCandidateProfileBadge" class="badge text-bg-info">Profil —</span>
|
<span id="replayCandidateProfileBadge" class="badge text-bg-info">Profil —</span>
|
||||||
@@ -30,402 +31,405 @@
|
|||||||
<main class="app-main">
|
<main class="app-main">
|
||||||
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
||||||
<div class="container-fluid px-4 py-4">
|
<div class="container-fluid px-4 py-4">
|
||||||
<div class="card shadow-sm border-0 mb-4">
|
<div class="row g-4 justify-content-center">
|
||||||
<div class="card-body">
|
<div class="col-12">
|
||||||
<h1 class="h3 card-title">Exploration read-only des candidats</h1>
|
<div class="card shadow-sm border-0 mb-4">
|
||||||
<p class="text-body-secondary mb-2">Les requêtes sont paramétrées, bornées et sans SQL libre. Utilisez les cases à cocher pour sélectionner les lignes. La case du header sélectionne ou désélectionne toutes les lignes correspondant au filtre local. Sans sélection explicite, la copie et l’export CSV utilisent toutes les lignes filtrées. Les CSV UTF-8 avec BOM et séparateur point-virgule sont écrits par le backend Tauri dans <code>./data/exports_csv/</code>. LibreOffice Calc peut toujours afficher son dialogue d’import, car le format CSV ne décrit pas formellement son encodage ni son séparateur.</p>
|
<div class="card-body">
|
||||||
<div class="small text-body-secondary">
|
<h1 class="h3 card-title">Exploration read-only des candidats</h1>
|
||||||
<span class="fw-semibold">DSN :</span>
|
<p class="text-body-secondary mb-2">Les requêtes sont paramétrées, bornées et sans SQL libre. Utilisez les cases à cocher pour sélectionner les lignes. La case du header sélectionne ou désélectionne toutes les lignes correspondant au filtre local. Sans sélection explicite, la copie et l’export CSV utilisent toutes les lignes filtrées. Les CSV UTF-8 avec BOM et séparateur point-virgule sont écrits par le backend Tauri dans <code>./data/exports_csv/</code>. LibreOffice Calc peut toujours afficher son dialogue d’import, car le format CSV ne décrit pas formellement son encodage ni son séparateur.</p>
|
||||||
<code id="replayCandidateDsn">—</code>
|
<div class="small text-body-secondary">
|
||||||
<span class="ms-3 fw-semibold">Limite serveur maximale :</span>
|
<span class="fw-semibold">DSN :</span>
|
||||||
<code id="replayCandidateMaximumLimit">—</code>
|
<code id="replayCandidateDsn">—</code>
|
||||||
|
<span class="ms-3 fw-semibold">Limite serveur maximale :</span>
|
||||||
|
<code id="replayCandidateMaximumLimit">—</code>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="nav nav-tabs mb-3" id="replayCandidateTabs" role="tablist">
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<button class="nav-link active" id="transactionsTabButton" data-bs-toggle="tab" data-bs-target="#transactionsTabPane" type="button" role="tab" aria-controls="transactionsTabPane" aria-selected="true">Transactions et signatures</button>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<button class="nav-link" id="programsTabButton" data-bs-toggle="tab" data-bs-target="#programsTabPane" type="button" role="tab" aria-controls="programsTabPane" aria-selected="false">Programmes</button>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<button class="nav-link" id="mintsTabButton" data-bs-toggle="tab" data-bs-target="#mintsTabPane" type="button" role="tab" aria-controls="mintsTabPane" aria-selected="false">Mints</button>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<button class="nav-link" id="ownersTabButton" data-bs-toggle="tab" data-bs-target="#ownersTabPane" type="button" role="tab" aria-controls="ownersTabPane" aria-selected="false">Owners</button>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<button class="nav-link" id="accountsTabButton" data-bs-toggle="tab" data-bs-target="#accountsTabPane" type="button" role="tab" aria-controls="accountsTabPane" aria-selected="false">Comptes</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="tab-content" id="replayCandidateTabContent">
|
||||||
|
<section class="tab-pane fade show active" id="transactionsTabPane" role="tabpanel" aria-labelledby="transactionsTabButton" tabindex="0">
|
||||||
|
<div class="card shadow-sm border-0 mb-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="h5 card-title">Filtres PostgreSQL bornés</h2>
|
||||||
|
<div class="row g-3 align-items-end">
|
||||||
|
<div class="col-12 col-xl-4">
|
||||||
|
<label for="transactionSignatureContainsInput" class="form-label">Signature contient</label>
|
||||||
|
<input id="transactionSignatureContainsInput" class="form-control font-monospace" type="text" autocomplete="off" />
|
||||||
|
</div>
|
||||||
|
<div class="col-6 col-md-3 col-xl-2">
|
||||||
|
<label for="transactionMinSlotInput" class="form-label">Slot minimum</label>
|
||||||
|
<input id="transactionMinSlotInput" class="form-control" type="number" min="0" step="1" />
|
||||||
|
</div>
|
||||||
|
<div class="col-6 col-md-3 col-xl-2">
|
||||||
|
<label for="transactionMaxSlotInput" class="form-label">Slot maximum</label>
|
||||||
|
<input id="transactionMaxSlotInput" class="form-control" type="number" min="0" step="1" />
|
||||||
|
</div>
|
||||||
|
<div class="col-6 col-md-3 col-xl-2">
|
||||||
|
<label for="transactionRawStateSelect" class="form-label">État raw</label>
|
||||||
|
<select id="transactionRawStateSelect" class="form-select">
|
||||||
|
<option value="">Tous</option>
|
||||||
|
<option value="received">received</option>
|
||||||
|
<option value="core_extracted">core_extracted</option>
|
||||||
|
<option value="decoded">decoded</option>
|
||||||
|
<option value="materialized">materialized</option>
|
||||||
|
<option value="failed">failed</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-6 col-md-3 col-xl-2">
|
||||||
|
<label for="transactionLedgerStatusSelect" class="form-label">Ledger core</label>
|
||||||
|
<select id="transactionLedgerStatusSelect" class="form-select">
|
||||||
|
<option value="">Tous</option>
|
||||||
|
<option value="not_started">not_started</option>
|
||||||
|
<option value="running">running</option>
|
||||||
|
<option value="succeeded">succeeded</option>
|
||||||
|
<option value="failed">failed</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-xl-5">
|
||||||
|
<label for="transactionProgramIdInput" class="form-label">Program ID exact</label>
|
||||||
|
<input id="transactionProgramIdInput" class="form-control font-monospace" type="text" list="knownProgramDatalist" autocomplete="off" />
|
||||||
|
</div>
|
||||||
|
<div class="col-6 col-md-3 col-xl-2">
|
||||||
|
<label for="transactionProgramScopeSelect" class="form-label">Portée programme</label>
|
||||||
|
<select id="transactionProgramScopeSelect" class="form-select">
|
||||||
|
<option value="any">outer + inner + logs</option>
|
||||||
|
<option value="outer">outer uniquement</option>
|
||||||
|
<option value="inner">inner uniquement</option>
|
||||||
|
<option value="logs">logs liés uniquement</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-6 col-md-3 col-xl-2">
|
||||||
|
<label for="transactionEntityKindSelect" class="form-label">Type d’entité</label>
|
||||||
|
<select id="transactionEntityKindSelect" class="form-select">
|
||||||
|
<option value="">Aucune</option>
|
||||||
|
<option value="mint">mint</option>
|
||||||
|
<option value="owner">owner</option>
|
||||||
|
<option value="account_key">account_key</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-xl-3">
|
||||||
|
<label for="transactionEntityValueInput" class="form-label">Entité exacte</label>
|
||||||
|
<input id="transactionEntityValueInput" class="form-control font-monospace" type="text" autocomplete="off" />
|
||||||
|
</div>
|
||||||
|
<div class="col-6 col-md-3 col-xl-1">
|
||||||
|
<label for="transactionLimitInput" class="form-label">Limite</label>
|
||||||
|
<input id="transactionLimitInput" class="form-control" type="number" min="1" max="5000" step="1" value="500" />
|
||||||
|
</div>
|
||||||
|
<div class="col-6 col-md-3 col-xl-2">
|
||||||
|
<div class="form-check form-switch mb-2">
|
||||||
|
<input id="transactionNewestFirstInput" class="form-check-input" type="checkbox" role="switch" checked />
|
||||||
|
<label class="form-check-label" for="transactionNewestFirstInput">Plus récents d’abord</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-xl-3">
|
||||||
|
<div class="d-grid d-sm-flex gap-2">
|
||||||
|
<button id="resetTransactionsButton" class="btn btn-outline-secondary" type="button">Réinitialiser</button>
|
||||||
|
<button id="loadTransactionsButton" class="btn btn-primary flex-grow-1" type="button">Charger les transactions</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card shadow-sm border-0">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
|
||||||
|
<div>
|
||||||
|
<h2 class="h5 card-title mb-1">Transactions candidates</h2>
|
||||||
|
<div id="transactionResultSummary" class="small text-body-secondary">Aucune requête exécutée.</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="btn-group flex-wrap" role="group" aria-label="Actions signatures">
|
||||||
|
<button id="copySignaturesButton" class="btn btn-sm btn-outline-primary" type="button">Copier signatures multiligne</button>
|
||||||
|
<button id="exportTransactionsCsvButton" class="btn btn-sm btn-outline-success" type="button">Exporter CSV</button>
|
||||||
|
</div>
|
||||||
|
<div class="small text-body-secondary mt-1">Les identifiants longs sont tronqués à l’écran. Survolez-les pour afficher leur valeur complète ou utilisez le bouton de copie individuel.</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table id="transactionCandidateTable" class="table table-striped table-hover table-sm align-middle w-100">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="replay-select-column"><span class="visually-hidden">Sélection</span></th>
|
||||||
|
<th>Signature</th>
|
||||||
|
<th>Slot</th>
|
||||||
|
<th>Raw</th>
|
||||||
|
<th title="État de présence core ; échec on-chain signifie que la transaction Solana a échoué, pas que l’extraction core a échoué.">Core</th>
|
||||||
|
<th>Ledger</th>
|
||||||
|
<th>Version</th>
|
||||||
|
<th>Essais</th>
|
||||||
|
<th data-bs-toggle="tooltip" title="Nombre total d’instructions top-level.">Outer inst.</th>
|
||||||
|
<th data-bs-toggle="tooltip" title="Nombre total d’instructions internes.">Inner inst.</th>
|
||||||
|
<th data-bs-toggle="tooltip" title="Nombre de program IDs distincts dans les instructions top-level.">Outer pr.</th>
|
||||||
|
<th data-bs-toggle="tooltip" title="Nombre de program IDs distincts dans les instructions internes.">Inner pr.</th>
|
||||||
|
<th>Mise à jour</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="tab-pane fade" id="programsTabPane" role="tabpanel" aria-labelledby="programsTabButton" tabindex="0">
|
||||||
|
<div class="card shadow-sm border-0 mb-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row g-3 align-items-end">
|
||||||
|
<div class="col-12 col-lg-5">
|
||||||
|
<label for="knownProgramSelect" class="form-label">Programme connu (kb_program_ids)</label>
|
||||||
|
<select id="knownProgramSelect" class="form-select">
|
||||||
|
<option value="">Tous les programmes connus</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-lg-4">
|
||||||
|
<label for="programContainsInput" class="form-label">Program ID contient</label>
|
||||||
|
<input id="programContainsInput" class="form-control font-monospace" type="text" list="knownProgramDatalist" autocomplete="off" />
|
||||||
|
</div>
|
||||||
|
<div class="col-6 col-lg-1">
|
||||||
|
<label for="programLimitInput" class="form-label">Limite</label>
|
||||||
|
<input id="programLimitInput" class="form-control" type="number" min="1" max="5000" step="1" value="500" />
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-lg-2">
|
||||||
|
<div class="d-grid gap-2">
|
||||||
|
<button id="resetProgramsButton" class="btn btn-outline-secondary" type="button">Réinitialiser</button>
|
||||||
|
<button id="loadProgramsButton" class="btn btn-primary" type="button">Charger les programmes</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card shadow-sm border-0">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
|
||||||
|
<div>
|
||||||
|
<h2 class="h5 card-title mb-1">Programmes indexés</h2>
|
||||||
|
<div id="programResultSummary" class="small text-body-secondary">Aucune requête exécutée.</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="btn-group flex-wrap" role="group" aria-label="Actions programmes">
|
||||||
|
<button id="useSelectedProgramButton" class="btn btn-sm btn-outline-secondary" type="button">Utiliser comme filtre transactions</button>
|
||||||
|
<button id="copyProgramsButton" class="btn btn-sm btn-outline-primary" type="button">Copier IDs multiligne</button>
|
||||||
|
<button id="exportProgramsCsvButton" class="btn btn-sm btn-outline-success" type="button">Exporter CSV</button>
|
||||||
|
</div>
|
||||||
|
<div class="small text-body-secondary mt-1">Cochez un programme. Sans sélection, l’action accepte une seule ligne restant après le filtre local.</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table id="programCandidateTable" class="table table-striped table-hover table-sm align-middle w-100">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="replay-select-column"><span class="visually-hidden">Sélection</span></th>
|
||||||
|
<th>Code connu</th>
|
||||||
|
<th>Program ID</th>
|
||||||
|
<th>Transactions</th>
|
||||||
|
<th>Outer</th>
|
||||||
|
<th>Inner</th>
|
||||||
|
<th>Logs liés</th>
|
||||||
|
<th>Slot min</th>
|
||||||
|
<th>Slot max</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="tab-pane fade" id="mintsTabPane" role="tabpanel" aria-labelledby="mintsTabButton" tabindex="0">
|
||||||
|
<div class="card shadow-sm border-0 mb-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row g-3 align-items-end">
|
||||||
|
<div class="col-12 col-lg-7">
|
||||||
|
<label for="mintContainsInput" class="form-label">Mint contient</label>
|
||||||
|
<input id="mintContainsInput" class="form-control font-monospace" type="text" autocomplete="off" />
|
||||||
|
</div>
|
||||||
|
<div class="col-6 col-lg-2">
|
||||||
|
<label for="mintLimitInput" class="form-label">Limite</label>
|
||||||
|
<input id="mintLimitInput" class="form-control" type="number" min="1" max="5000" step="1" value="500" />
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-lg-3">
|
||||||
|
<div class="d-grid d-sm-flex gap-2">
|
||||||
|
<button id="resetMintsButton" class="btn btn-outline-secondary" type="button">Réinitialiser</button>
|
||||||
|
<button id="loadMintsButton" class="btn btn-primary flex-grow-1" type="button">Charger les mints</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card shadow-sm border-0">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
|
||||||
|
<div>
|
||||||
|
<h2 class="h5 card-title mb-1">Mints</h2>
|
||||||
|
<div id="mintResultSummary" class="small text-body-secondary">Aucune requête exécutée.</div>
|
||||||
|
<div class="small text-body-secondary">Source : <code>kb_sol_core_balance_changes.mint</code>.</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="btn-group flex-wrap" role="group" aria-label="Actions mints">
|
||||||
|
<button id="useSelectedMintsButton" class="btn btn-sm btn-outline-secondary" type="button">Utiliser comme filtre transactions</button>
|
||||||
|
<button id="copyMintsButton" class="btn btn-sm btn-outline-primary" type="button">Copier valeurs multiligne</button>
|
||||||
|
<button id="exportMintsCsvButton" class="btn btn-sm btn-outline-success" type="button">Exporter CSV</button>
|
||||||
|
</div>
|
||||||
|
<div class="small text-body-secondary mt-1">Cochez une ligne. Sans sélection, l’action accepte une seule ligne restant après le filtre local.</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table id="mintCandidateTable" class="table table-striped table-hover table-sm align-middle w-100">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="replay-select-column"><span class="visually-hidden">Sélection</span></th>
|
||||||
|
<th>Mint</th>
|
||||||
|
<th data-bs-toggle="tooltip" title="Nombre de signatures distinctes dans lesquelles la valeur apparaît.">Transactions</th>
|
||||||
|
<th data-bs-toggle="tooltip" title="Nombre total de lignes core portant cette valeur.">Occurrences</th>
|
||||||
|
<th data-bs-toggle="tooltip" title="Occurrences divisées par le nombre de transactions distinctes.">Occ./tx</th>
|
||||||
|
<th data-bs-toggle="tooltip" title="Premier slot observé dans le corpus core.">Slot min</th>
|
||||||
|
<th data-bs-toggle="tooltip" title="Dernier slot observé dans le corpus core.">Slot max</th>
|
||||||
|
<th data-bs-toggle="tooltip" title="Différence entre le slot maximal et le slot minimal.">Étendue</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="tab-pane fade" id="ownersTabPane" role="tabpanel" aria-labelledby="ownersTabButton" tabindex="0">
|
||||||
|
<div class="card shadow-sm border-0 mb-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row g-3 align-items-end">
|
||||||
|
<div class="col-12 col-lg-7">
|
||||||
|
<label for="ownerContainsInput" class="form-label">Owner contient</label>
|
||||||
|
<input id="ownerContainsInput" class="form-control font-monospace" type="text" autocomplete="off" />
|
||||||
|
</div>
|
||||||
|
<div class="col-6 col-lg-2">
|
||||||
|
<label for="ownerLimitInput" class="form-label">Limite</label>
|
||||||
|
<input id="ownerLimitInput" class="form-control" type="number" min="1" max="5000" step="1" value="500" />
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-lg-3">
|
||||||
|
<div class="d-grid d-sm-flex gap-2">
|
||||||
|
<button id="resetOwnersButton" class="btn btn-outline-secondary" type="button">Réinitialiser</button>
|
||||||
|
<button id="loadOwnersButton" class="btn btn-primary flex-grow-1" type="button">Charger les owners</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card shadow-sm border-0">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
|
||||||
|
<div>
|
||||||
|
<h2 class="h5 card-title mb-1">Owners</h2>
|
||||||
|
<div id="ownerResultSummary" class="small text-body-secondary">Aucune requête exécutée.</div>
|
||||||
|
<div class="small text-body-secondary">Source : <code>kb_sol_core_balance_changes.owner</code>.</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="btn-group flex-wrap" role="group" aria-label="Actions owners">
|
||||||
|
<button id="useSelectedOwnersButton" class="btn btn-sm btn-outline-secondary" type="button">Utiliser comme filtre transactions</button>
|
||||||
|
<button id="copyOwnersButton" class="btn btn-sm btn-outline-primary" type="button">Copier valeurs multiligne</button>
|
||||||
|
<button id="exportOwnersCsvButton" class="btn btn-sm btn-outline-success" type="button">Exporter CSV</button>
|
||||||
|
</div>
|
||||||
|
<div class="small text-body-secondary mt-1">Cochez une ligne. Sans sélection, l’action accepte une seule ligne restant après le filtre local.</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table id="ownerCandidateTable" class="table table-striped table-hover table-sm align-middle w-100">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="replay-select-column"><span class="visually-hidden">Sélection</span></th>
|
||||||
|
<th>Owner</th>
|
||||||
|
<th data-bs-toggle="tooltip" title="Nombre de signatures distinctes dans lesquelles la valeur apparaît.">Transactions</th>
|
||||||
|
<th data-bs-toggle="tooltip" title="Nombre total de lignes core portant cette valeur.">Occurrences</th>
|
||||||
|
<th data-bs-toggle="tooltip" title="Occurrences divisées par le nombre de transactions distinctes.">Occ./tx</th>
|
||||||
|
<th data-bs-toggle="tooltip" title="Premier slot observé dans le corpus core.">Slot min</th>
|
||||||
|
<th data-bs-toggle="tooltip" title="Dernier slot observé dans le corpus core.">Slot max</th>
|
||||||
|
<th data-bs-toggle="tooltip" title="Différence entre le slot maximal et le slot minimal.">Étendue</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="tab-pane fade" id="accountsTabPane" role="tabpanel" aria-labelledby="accountsTabButton" tabindex="0">
|
||||||
|
<div class="card shadow-sm border-0 mb-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row g-3 align-items-end">
|
||||||
|
<div class="col-12 col-lg-7">
|
||||||
|
<label for="accountContainsInput" class="form-label">Account key contient</label>
|
||||||
|
<input id="accountContainsInput" class="form-control font-monospace" type="text" autocomplete="off" />
|
||||||
|
</div>
|
||||||
|
<div class="col-6 col-lg-2">
|
||||||
|
<label for="accountLimitInput" class="form-label">Limite</label>
|
||||||
|
<input id="accountLimitInput" class="form-control" type="number" min="1" max="5000" step="1" value="500" />
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-lg-3">
|
||||||
|
<div class="d-grid d-sm-flex gap-2">
|
||||||
|
<button id="resetAccountsButton" class="btn btn-outline-secondary" type="button">Réinitialiser</button>
|
||||||
|
<button id="loadAccountsButton" class="btn btn-primary flex-grow-1" type="button">Charger les comptes</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card shadow-sm border-0">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
|
||||||
|
<div>
|
||||||
|
<h2 class="h5 card-title mb-1">Comptes</h2>
|
||||||
|
<div id="accountResultSummary" class="small text-body-secondary">Aucune requête exécutée.</div>
|
||||||
|
<div class="small text-body-secondary">Source : <code>kb_sol_core_account_keys.account_key</code>.</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="btn-group flex-wrap" role="group" aria-label="Actions comptes">
|
||||||
|
<button id="useSelectedAccountsButton" class="btn btn-sm btn-outline-secondary" type="button">Utiliser comme filtre transactions</button>
|
||||||
|
<button id="copyAccountsButton" class="btn btn-sm btn-outline-primary" type="button">Copier valeurs multiligne</button>
|
||||||
|
<button id="exportAccountsCsvButton" class="btn btn-sm btn-outline-success" type="button">Exporter CSV</button>
|
||||||
|
</div>
|
||||||
|
<div class="small text-body-secondary mt-1">Cochez une ligne. Sans sélection, l’action accepte une seule ligne restant après le filtre local.</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table id="accountCandidateTable" class="table table-striped table-hover table-sm align-middle w-100">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="replay-select-column"><span class="visually-hidden">Sélection</span></th>
|
||||||
|
<th>Account key</th>
|
||||||
|
<th data-bs-toggle="tooltip" title="Nombre de signatures distinctes dans lesquelles la valeur apparaît.">Transactions</th>
|
||||||
|
<th data-bs-toggle="tooltip" title="Nombre total de lignes core portant cette valeur.">Occurrences</th>
|
||||||
|
<th data-bs-toggle="tooltip" title="Occurrences divisées par le nombre de transactions distinctes.">Occ./tx</th>
|
||||||
|
<th data-bs-toggle="tooltip" title="Premier slot observé dans le corpus core.">Slot min</th>
|
||||||
|
<th data-bs-toggle="tooltip" title="Dernier slot observé dans le corpus core.">Slot max</th>
|
||||||
|
<th data-bs-toggle="tooltip" title="Différence entre le slot maximal et le slot minimal.">Étendue</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="nav nav-tabs mb-3" id="replayCandidateTabs" role="tablist">
|
|
||||||
<li class="nav-item" role="presentation">
|
|
||||||
<button class="nav-link active" id="transactionsTabButton" data-bs-toggle="tab" data-bs-target="#transactionsTabPane" type="button" role="tab" aria-controls="transactionsTabPane" aria-selected="true">Transactions et signatures</button>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item" role="presentation">
|
|
||||||
<button class="nav-link" id="programsTabButton" data-bs-toggle="tab" data-bs-target="#programsTabPane" type="button" role="tab" aria-controls="programsTabPane" aria-selected="false">Programmes</button>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item" role="presentation">
|
|
||||||
<button class="nav-link" id="mintsTabButton" data-bs-toggle="tab" data-bs-target="#mintsTabPane" type="button" role="tab" aria-controls="mintsTabPane" aria-selected="false">Mints</button>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item" role="presentation">
|
|
||||||
<button class="nav-link" id="ownersTabButton" data-bs-toggle="tab" data-bs-target="#ownersTabPane" type="button" role="tab" aria-controls="ownersTabPane" aria-selected="false">Owners</button>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item" role="presentation">
|
|
||||||
<button class="nav-link" id="accountsTabButton" data-bs-toggle="tab" data-bs-target="#accountsTabPane" type="button" role="tab" aria-controls="accountsTabPane" aria-selected="false">Comptes</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div class="tab-content" id="replayCandidateTabContent">
|
|
||||||
<section class="tab-pane fade show active" id="transactionsTabPane" role="tabpanel" aria-labelledby="transactionsTabButton" tabindex="0">
|
|
||||||
<div class="card shadow-sm border-0 mb-4">
|
|
||||||
<div class="card-body">
|
|
||||||
<h2 class="h5 card-title">Filtres PostgreSQL bornés</h2>
|
|
||||||
<div class="row g-3 align-items-end">
|
|
||||||
<div class="col-12 col-xl-4">
|
|
||||||
<label for="transactionSignatureContainsInput" class="form-label">Signature contient</label>
|
|
||||||
<input id="transactionSignatureContainsInput" class="form-control font-monospace" type="text" autocomplete="off" />
|
|
||||||
</div>
|
|
||||||
<div class="col-6 col-md-3 col-xl-2">
|
|
||||||
<label for="transactionMinSlotInput" class="form-label">Slot minimum</label>
|
|
||||||
<input id="transactionMinSlotInput" class="form-control" type="number" min="0" step="1" />
|
|
||||||
</div>
|
|
||||||
<div class="col-6 col-md-3 col-xl-2">
|
|
||||||
<label for="transactionMaxSlotInput" class="form-label">Slot maximum</label>
|
|
||||||
<input id="transactionMaxSlotInput" class="form-control" type="number" min="0" step="1" />
|
|
||||||
</div>
|
|
||||||
<div class="col-6 col-md-3 col-xl-2">
|
|
||||||
<label for="transactionRawStateSelect" class="form-label">État raw</label>
|
|
||||||
<select id="transactionRawStateSelect" class="form-select">
|
|
||||||
<option value="">Tous</option>
|
|
||||||
<option value="received">received</option>
|
|
||||||
<option value="core_extracted">core_extracted</option>
|
|
||||||
<option value="decoded">decoded</option>
|
|
||||||
<option value="materialized">materialized</option>
|
|
||||||
<option value="failed">failed</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-6 col-md-3 col-xl-2">
|
|
||||||
<label for="transactionLedgerStatusSelect" class="form-label">Ledger core</label>
|
|
||||||
<select id="transactionLedgerStatusSelect" class="form-select">
|
|
||||||
<option value="">Tous</option>
|
|
||||||
<option value="not_started">not_started</option>
|
|
||||||
<option value="running">running</option>
|
|
||||||
<option value="succeeded">succeeded</option>
|
|
||||||
<option value="failed">failed</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-xl-5">
|
|
||||||
<label for="transactionProgramIdInput" class="form-label">Program ID exact</label>
|
|
||||||
<input id="transactionProgramIdInput" class="form-control font-monospace" type="text" list="knownProgramDatalist" autocomplete="off" />
|
|
||||||
</div>
|
|
||||||
<div class="col-6 col-md-3 col-xl-2">
|
|
||||||
<label for="transactionProgramScopeSelect" class="form-label">Portée programme</label>
|
|
||||||
<select id="transactionProgramScopeSelect" class="form-select">
|
|
||||||
<option value="any">outer + inner + logs</option>
|
|
||||||
<option value="outer">outer uniquement</option>
|
|
||||||
<option value="inner">inner uniquement</option>
|
|
||||||
<option value="logs">logs liés uniquement</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-6 col-md-3 col-xl-2">
|
|
||||||
<label for="transactionEntityKindSelect" class="form-label">Type d’entité</label>
|
|
||||||
<select id="transactionEntityKindSelect" class="form-select">
|
|
||||||
<option value="">Aucune</option>
|
|
||||||
<option value="mint">mint</option>
|
|
||||||
<option value="owner">owner</option>
|
|
||||||
<option value="account_key">account_key</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-xl-3">
|
|
||||||
<label for="transactionEntityValueInput" class="form-label">Entité exacte</label>
|
|
||||||
<input id="transactionEntityValueInput" class="form-control font-monospace" type="text" autocomplete="off" />
|
|
||||||
</div>
|
|
||||||
<div class="col-6 col-md-3 col-xl-1">
|
|
||||||
<label for="transactionLimitInput" class="form-label">Limite</label>
|
|
||||||
<input id="transactionLimitInput" class="form-control" type="number" min="1" max="5000" step="1" value="500" />
|
|
||||||
</div>
|
|
||||||
<div class="col-6 col-md-3 col-xl-2">
|
|
||||||
<div class="form-check form-switch mb-2">
|
|
||||||
<input id="transactionNewestFirstInput" class="form-check-input" type="checkbox" role="switch" checked />
|
|
||||||
<label class="form-check-label" for="transactionNewestFirstInput">Plus récents d’abord</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-xl-3">
|
|
||||||
<div class="d-grid d-sm-flex gap-2">
|
|
||||||
<button id="resetTransactionsButton" class="btn btn-outline-secondary" type="button">Réinitialiser</button>
|
|
||||||
<button id="loadTransactionsButton" class="btn btn-primary flex-grow-1" type="button">Charger les transactions</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card shadow-sm border-0">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
|
|
||||||
<div>
|
|
||||||
<h2 class="h5 card-title mb-1">Transactions candidates</h2>
|
|
||||||
<div id="transactionResultSummary" class="small text-body-secondary">Aucune requête exécutée.</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="btn-group flex-wrap" role="group" aria-label="Actions signatures">
|
|
||||||
<button id="copySignaturesButton" class="btn btn-sm btn-outline-primary" type="button">Copier signatures multiligne</button>
|
|
||||||
<button id="exportTransactionsCsvButton" class="btn btn-sm btn-outline-success" type="button">Exporter CSV</button>
|
|
||||||
</div>
|
|
||||||
<div class="small text-body-secondary mt-1">Les identifiants longs sont tronqués à l’écran. Survolez-les pour afficher leur valeur complète ou utilisez le bouton de copie individuel.</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table id="transactionCandidateTable" class="table table-striped table-hover table-sm align-middle w-100">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="replay-select-column"><span class="visually-hidden">Sélection</span></th>
|
|
||||||
<th>Signature</th>
|
|
||||||
<th>Slot</th>
|
|
||||||
<th>Raw</th>
|
|
||||||
<th title="État de présence core ; échec on-chain signifie que la transaction Solana a échoué, pas que l’extraction core a échoué.">Core</th>
|
|
||||||
<th>Ledger</th>
|
|
||||||
<th>Version</th>
|
|
||||||
<th>Essais</th>
|
|
||||||
<th data-bs-toggle="tooltip" title="Nombre total d’instructions top-level.">Outer inst.</th>
|
|
||||||
<th data-bs-toggle="tooltip" title="Nombre total d’instructions internes.">Inner inst.</th>
|
|
||||||
<th data-bs-toggle="tooltip" title="Nombre de program IDs distincts dans les instructions top-level.">Outer pr.</th>
|
|
||||||
<th data-bs-toggle="tooltip" title="Nombre de program IDs distincts dans les instructions internes.">Inner pr.</th>
|
|
||||||
<th>Mise à jour</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="tab-pane fade" id="programsTabPane" role="tabpanel" aria-labelledby="programsTabButton" tabindex="0">
|
|
||||||
<div class="card shadow-sm border-0 mb-4">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="row g-3 align-items-end">
|
|
||||||
<div class="col-12 col-lg-5">
|
|
||||||
<label for="knownProgramSelect" class="form-label">Programme connu (kb_program_ids)</label>
|
|
||||||
<select id="knownProgramSelect" class="form-select">
|
|
||||||
<option value="">Tous les programmes connus</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-lg-4">
|
|
||||||
<label for="programContainsInput" class="form-label">Program ID contient</label>
|
|
||||||
<input id="programContainsInput" class="form-control font-monospace" type="text" list="knownProgramDatalist" autocomplete="off" />
|
|
||||||
</div>
|
|
||||||
<div class="col-6 col-lg-1">
|
|
||||||
<label for="programLimitInput" class="form-label">Limite</label>
|
|
||||||
<input id="programLimitInput" class="form-control" type="number" min="1" max="5000" step="1" value="500" />
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-lg-2">
|
|
||||||
<div class="d-grid gap-2">
|
|
||||||
<button id="resetProgramsButton" class="btn btn-outline-secondary" type="button">Réinitialiser</button>
|
|
||||||
<button id="loadProgramsButton" class="btn btn-primary" type="button">Charger les programmes</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card shadow-sm border-0">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
|
|
||||||
<div>
|
|
||||||
<h2 class="h5 card-title mb-1">Programmes indexés</h2>
|
|
||||||
<div id="programResultSummary" class="small text-body-secondary">Aucune requête exécutée.</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="btn-group flex-wrap" role="group" aria-label="Actions programmes">
|
|
||||||
<button id="useSelectedProgramButton" class="btn btn-sm btn-outline-secondary" type="button">Utiliser comme filtre transactions</button>
|
|
||||||
<button id="copyProgramsButton" class="btn btn-sm btn-outline-primary" type="button">Copier IDs multiligne</button>
|
|
||||||
<button id="exportProgramsCsvButton" class="btn btn-sm btn-outline-success" type="button">Exporter CSV</button>
|
|
||||||
</div>
|
|
||||||
<div class="small text-body-secondary mt-1">Cochez un programme. Sans sélection, l’action accepte une seule ligne restant après le filtre local.</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table id="programCandidateTable" class="table table-striped table-hover table-sm align-middle w-100">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="replay-select-column"><span class="visually-hidden">Sélection</span></th>
|
|
||||||
<th>Code connu</th>
|
|
||||||
<th>Program ID</th>
|
|
||||||
<th>Transactions</th>
|
|
||||||
<th>Outer</th>
|
|
||||||
<th>Inner</th>
|
|
||||||
<th>Logs liés</th>
|
|
||||||
<th>Slot min</th>
|
|
||||||
<th>Slot max</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="tab-pane fade" id="mintsTabPane" role="tabpanel" aria-labelledby="mintsTabButton" tabindex="0">
|
|
||||||
<div class="card shadow-sm border-0 mb-4">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="row g-3 align-items-end">
|
|
||||||
<div class="col-12 col-lg-7">
|
|
||||||
<label for="mintContainsInput" class="form-label">Mint contient</label>
|
|
||||||
<input id="mintContainsInput" class="form-control font-monospace" type="text" autocomplete="off" />
|
|
||||||
</div>
|
|
||||||
<div class="col-6 col-lg-2">
|
|
||||||
<label for="mintLimitInput" class="form-label">Limite</label>
|
|
||||||
<input id="mintLimitInput" class="form-control" type="number" min="1" max="5000" step="1" value="500" />
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-lg-3">
|
|
||||||
<div class="d-grid d-sm-flex gap-2">
|
|
||||||
<button id="resetMintsButton" class="btn btn-outline-secondary" type="button">Réinitialiser</button>
|
|
||||||
<button id="loadMintsButton" class="btn btn-primary flex-grow-1" type="button">Charger les mints</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card shadow-sm border-0">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
|
|
||||||
<div>
|
|
||||||
<h2 class="h5 card-title mb-1">Mints</h2>
|
|
||||||
<div id="mintResultSummary" class="small text-body-secondary">Aucune requête exécutée.</div>
|
|
||||||
<div class="small text-body-secondary">Source : <code>kb_sol_core_balance_changes.mint</code>.</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="btn-group flex-wrap" role="group" aria-label="Actions mints">
|
|
||||||
<button id="useSelectedMintsButton" class="btn btn-sm btn-outline-secondary" type="button">Utiliser comme filtre transactions</button>
|
|
||||||
<button id="copyMintsButton" class="btn btn-sm btn-outline-primary" type="button">Copier valeurs multiligne</button>
|
|
||||||
<button id="exportMintsCsvButton" class="btn btn-sm btn-outline-success" type="button">Exporter CSV</button>
|
|
||||||
</div>
|
|
||||||
<div class="small text-body-secondary mt-1">Cochez une ligne. Sans sélection, l’action accepte une seule ligne restant après le filtre local.</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table id="mintCandidateTable" class="table table-striped table-hover table-sm align-middle w-100">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="replay-select-column"><span class="visually-hidden">Sélection</span></th>
|
|
||||||
<th>Mint</th>
|
|
||||||
<th data-bs-toggle="tooltip" title="Nombre de signatures distinctes dans lesquelles la valeur apparaît.">Transactions</th>
|
|
||||||
<th data-bs-toggle="tooltip" title="Nombre total de lignes core portant cette valeur.">Occurrences</th>
|
|
||||||
<th data-bs-toggle="tooltip" title="Occurrences divisées par le nombre de transactions distinctes.">Occ./tx</th>
|
|
||||||
<th data-bs-toggle="tooltip" title="Premier slot observé dans le corpus core.">Slot min</th>
|
|
||||||
<th data-bs-toggle="tooltip" title="Dernier slot observé dans le corpus core.">Slot max</th>
|
|
||||||
<th data-bs-toggle="tooltip" title="Différence entre le slot maximal et le slot minimal.">Étendue</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="tab-pane fade" id="ownersTabPane" role="tabpanel" aria-labelledby="ownersTabButton" tabindex="0">
|
|
||||||
<div class="card shadow-sm border-0 mb-4">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="row g-3 align-items-end">
|
|
||||||
<div class="col-12 col-lg-7">
|
|
||||||
<label for="ownerContainsInput" class="form-label">Owner contient</label>
|
|
||||||
<input id="ownerContainsInput" class="form-control font-monospace" type="text" autocomplete="off" />
|
|
||||||
</div>
|
|
||||||
<div class="col-6 col-lg-2">
|
|
||||||
<label for="ownerLimitInput" class="form-label">Limite</label>
|
|
||||||
<input id="ownerLimitInput" class="form-control" type="number" min="1" max="5000" step="1" value="500" />
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-lg-3">
|
|
||||||
<div class="d-grid d-sm-flex gap-2">
|
|
||||||
<button id="resetOwnersButton" class="btn btn-outline-secondary" type="button">Réinitialiser</button>
|
|
||||||
<button id="loadOwnersButton" class="btn btn-primary flex-grow-1" type="button">Charger les owners</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card shadow-sm border-0">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
|
|
||||||
<div>
|
|
||||||
<h2 class="h5 card-title mb-1">Owners</h2>
|
|
||||||
<div id="ownerResultSummary" class="small text-body-secondary">Aucune requête exécutée.</div>
|
|
||||||
<div class="small text-body-secondary">Source : <code>kb_sol_core_balance_changes.owner</code>.</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="btn-group flex-wrap" role="group" aria-label="Actions owners">
|
|
||||||
<button id="useSelectedOwnersButton" class="btn btn-sm btn-outline-secondary" type="button">Utiliser comme filtre transactions</button>
|
|
||||||
<button id="copyOwnersButton" class="btn btn-sm btn-outline-primary" type="button">Copier valeurs multiligne</button>
|
|
||||||
<button id="exportOwnersCsvButton" class="btn btn-sm btn-outline-success" type="button">Exporter CSV</button>
|
|
||||||
</div>
|
|
||||||
<div class="small text-body-secondary mt-1">Cochez une ligne. Sans sélection, l’action accepte une seule ligne restant après le filtre local.</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table id="ownerCandidateTable" class="table table-striped table-hover table-sm align-middle w-100">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="replay-select-column"><span class="visually-hidden">Sélection</span></th>
|
|
||||||
<th>Owner</th>
|
|
||||||
<th data-bs-toggle="tooltip" title="Nombre de signatures distinctes dans lesquelles la valeur apparaît.">Transactions</th>
|
|
||||||
<th data-bs-toggle="tooltip" title="Nombre total de lignes core portant cette valeur.">Occurrences</th>
|
|
||||||
<th data-bs-toggle="tooltip" title="Occurrences divisées par le nombre de transactions distinctes.">Occ./tx</th>
|
|
||||||
<th data-bs-toggle="tooltip" title="Premier slot observé dans le corpus core.">Slot min</th>
|
|
||||||
<th data-bs-toggle="tooltip" title="Dernier slot observé dans le corpus core.">Slot max</th>
|
|
||||||
<th data-bs-toggle="tooltip" title="Différence entre le slot maximal et le slot minimal.">Étendue</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="tab-pane fade" id="accountsTabPane" role="tabpanel" aria-labelledby="accountsTabButton" tabindex="0">
|
|
||||||
<div class="card shadow-sm border-0 mb-4">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="row g-3 align-items-end">
|
|
||||||
<div class="col-12 col-lg-7">
|
|
||||||
<label for="accountContainsInput" class="form-label">Account key contient</label>
|
|
||||||
<input id="accountContainsInput" class="form-control font-monospace" type="text" autocomplete="off" />
|
|
||||||
</div>
|
|
||||||
<div class="col-6 col-lg-2">
|
|
||||||
<label for="accountLimitInput" class="form-label">Limite</label>
|
|
||||||
<input id="accountLimitInput" class="form-control" type="number" min="1" max="5000" step="1" value="500" />
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-lg-3">
|
|
||||||
<div class="d-grid d-sm-flex gap-2">
|
|
||||||
<button id="resetAccountsButton" class="btn btn-outline-secondary" type="button">Réinitialiser</button>
|
|
||||||
<button id="loadAccountsButton" class="btn btn-primary flex-grow-1" type="button">Charger les comptes</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card shadow-sm border-0">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
|
|
||||||
<div>
|
|
||||||
<h2 class="h5 card-title mb-1">Comptes</h2>
|
|
||||||
<div id="accountResultSummary" class="small text-body-secondary">Aucune requête exécutée.</div>
|
|
||||||
<div class="small text-body-secondary">Source : <code>kb_sol_core_account_keys.account_key</code>.</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="btn-group flex-wrap" role="group" aria-label="Actions comptes">
|
|
||||||
<button id="useSelectedAccountsButton" class="btn btn-sm btn-outline-secondary" type="button">Utiliser comme filtre transactions</button>
|
|
||||||
<button id="copyAccountsButton" class="btn btn-sm btn-outline-primary" type="button">Copier valeurs multiligne</button>
|
|
||||||
<button id="exportAccountsCsvButton" class="btn btn-sm btn-outline-success" type="button">Exporter CSV</button>
|
|
||||||
</div>
|
|
||||||
<div class="small text-body-secondary mt-1">Cochez une ligne. Sans sélection, l’action accepte une seule ligne restant après le filtre local.</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table id="accountCandidateTable" class="table table-striped table-hover table-sm align-middle w-100">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="replay-select-column"><span class="visually-hidden">Sélection</span></th>
|
|
||||||
<th>Account key</th>
|
|
||||||
<th data-bs-toggle="tooltip" title="Nombre de signatures distinctes dans lesquelles la valeur apparaît.">Transactions</th>
|
|
||||||
<th data-bs-toggle="tooltip" title="Nombre total de lignes core portant cette valeur.">Occurrences</th>
|
|
||||||
<th data-bs-toggle="tooltip" title="Occurrences divisées par le nombre de transactions distinctes.">Occ./tx</th>
|
|
||||||
<th data-bs-toggle="tooltip" title="Premier slot observé dans le corpus core.">Slot min</th>
|
|
||||||
<th data-bs-toggle="tooltip" title="Dernier slot observé dans le corpus core.">Slot max</th>
|
|
||||||
<th data-bs-toggle="tooltip" title="Différence entre le slot maximal et le slot minimal.">Étendue</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<footer class="app-footer bg-dark text-light">
|
<footer class="app-footer bg-dark text-light">
|
||||||
@@ -435,9 +439,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<datalist id="knownProgramDatalist"></datalist>
|
<datalist id="knownProgramDatalist"></datalist>
|
||||||
<script type="module" src="ts/demo_sql_replay_candidates.ts" defer></script>
|
<script type="module" src="ts/demo_sql_replay_candidates.ts" defer></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -1,22 +1,23 @@
|
|||||||
<!-- file: kb-app-demo-desktop/frontend/demo_ws.html -->
|
<!-- file: kb-app-demo-desktop/frontend/demo_ws.html -->
|
||||||
<!-- version: 6 -->
|
<!-- version: 7 -->
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||||
<title>Khadhroony Bot3 - WebSocket standard</title>
|
<link rel="icon" href="imgs/favicon.png">
|
||||||
<link rel="stylesheet" href="sass/main.scss" />
|
<link rel="stylesheet" href="sass/main.scss">
|
||||||
|
<title>Khadhroony Bot3 — WebSocket standard</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="bg-body-tertiary">
|
<body>
|
||||||
<header class="app-header">
|
<header class="app-header">
|
||||||
<nav class="navbar navbar-expand-lg h-100 py-0 bg-light text-dark">
|
<nav class="navbar navbar-expand-lg h-100 py-0 bg-light text-dark">
|
||||||
<div class="container my-0">
|
<div class="container-fluid px-4 my-0">
|
||||||
<div class="navbar-brand d-flex align-items-center">
|
<div class="navbar-brand d-flex align-items-center">
|
||||||
<img alt="Logo" src="imgs/logo.png" class="app-logo" />
|
<img alt="Logo" src="imgs/logo.png" class="app-logo">
|
||||||
<span class="ps-2 fs-4 fw-bold text-primary font-logo">WebSocket standard</span>
|
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3 — <span class="badge text-bg-primary">WebSocket standard</span></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
@@ -24,9 +25,9 @@
|
|||||||
|
|
||||||
<main class="app-main">
|
<main class="app-main">
|
||||||
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
||||||
<div class="container py-4">
|
<div class="container-fluid px-4 py-4">
|
||||||
<div class="row g-4">
|
<div class="row g-4 justify-content-center">
|
||||||
<div class="col-12 col-xl-5">
|
<div class="col-12">
|
||||||
<div class="card shadow-sm border-0">
|
<div class="card shadow-sm border-0">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h1 class="h4 card-title">Souscription WebSocket Solana standard</h1>
|
<h1 class="h4 card-title">Souscription WebSocket Solana standard</h1>
|
||||||
@@ -106,8 +107,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script type="module" src="ts/demo_ws.ts" defer></script>
|
<script type="module" src="ts/demo_ws.ts" defer></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -1,20 +1,23 @@
|
|||||||
<!-- file: kb-app-demo-desktop/frontend/main.html -->
|
<!-- file: kb-app-demo-desktop/frontend/main.html -->
|
||||||
<!-- version: 7 -->
|
<!-- version: 8 -->
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||||
<title>Khadhroony Bot3</title>
|
<link rel="icon" href="imgs/favicon.png">
|
||||||
<link rel="stylesheet" href="sass/main.scss" />
|
<link rel="stylesheet" href="sass/main.scss">
|
||||||
|
<title>Khadhroony Bot3 — Main Window</title>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-body-tertiary">
|
|
||||||
|
<body>
|
||||||
<header class="app-header">
|
<header class="app-header">
|
||||||
<nav class="navbar navbar-expand-lg h-100 py-0 bg-light text-dark">
|
<nav class="navbar navbar-expand-lg h-100 py-0 bg-light text-dark">
|
||||||
<div class="container my-0">
|
<div class="container-fluid px-4 my-0">
|
||||||
<div class="navbar-brand d-flex align-items-center" aria-label="Khadhroony Bot3">
|
<div class="navbar-brand d-flex align-items-center">
|
||||||
<img alt="Logo Khadhroony" src="imgs/logo.png" class="app-logo" />
|
<img alt="Logo" src="imgs/logo.png" class="app-logo">
|
||||||
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3</span>
|
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3 — <span class="badge text-bg-primary">Main</span></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-auto d-flex align-items-center gap-2">
|
<div class="ms-auto d-flex align-items-center gap-2">
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
@@ -23,23 +26,39 @@
|
|||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu dropdown-menu-end">
|
<ul class="dropdown-menu dropdown-menu-end">
|
||||||
<li><a id="openDemoConfigLink" class="dropdown-item" href="#">Configuration</a></li>
|
<li><a id="openDemoConfigLink" class="dropdown-item" href="#">Configuration</a></li>
|
||||||
<li><hr class="dropdown-divider"></li>
|
<li>
|
||||||
<li><h6 class="dropdown-header">Transport et collecte</h6></li>
|
<hr class="dropdown-divider">
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<h6 class="dropdown-header">Transport et collecte</h6>
|
||||||
|
</li>
|
||||||
<li><a id="openDemoHttpLink" class="dropdown-item" href="#">HTTP JSON-RPC</a></li>
|
<li><a id="openDemoHttpLink" class="dropdown-item" href="#">HTTP JSON-RPC</a></li>
|
||||||
<li><a id="openDemoWsLink" class="dropdown-item" href="#">WebSocket standard</a></li>
|
<li><a id="openDemoWsLink" class="dropdown-item" href="#">WebSocket standard</a></li>
|
||||||
<li><a id="openDemoBackfillLink" class="dropdown-item" href="#">Backfill HTTP</a></li>
|
<li><a id="openDemoBackfillLink" class="dropdown-item" href="#">Backfill HTTP</a></li>
|
||||||
<li><hr class="dropdown-divider"></li>
|
<li>
|
||||||
<li><h6 class="dropdown-header">Pipeline</h6></li>
|
<hr class="dropdown-divider">
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<h6 class="dropdown-header">Pipeline</h6>
|
||||||
|
</li>
|
||||||
<li><a id="openDemoCoreExtractionLink" class="dropdown-item" href="#">Extraction core</a></li>
|
<li><a id="openDemoCoreExtractionLink" class="dropdown-item" href="#">Extraction core</a></li>
|
||||||
<li><a id="openDemoDecodeReplayLink" class="dropdown-item" href="#">Décodage contextualisé</a></li>
|
<li><a id="openDemoDecodeReplayLink" class="dropdown-item" href="#">Décodage contextualisé</a></li>
|
||||||
<li><hr class="dropdown-divider"></li>
|
<li>
|
||||||
<li><h6 class="dropdown-header">Stockage</h6></li>
|
<hr class="dropdown-divider">
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<h6 class="dropdown-header">Stockage</h6>
|
||||||
|
</li>
|
||||||
<li><a id="openDemoSqlDiagLink" class="dropdown-item" href="#">SQL diagnostics</a></li>
|
<li><a id="openDemoSqlDiagLink" class="dropdown-item" href="#">SQL diagnostics</a></li>
|
||||||
<li><a id="openDemoSqlPgRawLink" class="dropdown-item" href="#">SQL PostgreSQL raw</a></li>
|
<li><a id="openDemoSqlPgRawLink" class="dropdown-item" href="#">SQL PostgreSQL raw</a></li>
|
||||||
<li><a id="openDemoSqlPgCoreLink" class="dropdown-item" href="#">SQL PostgreSQL core</a></li>
|
<li><a id="openDemoSqlPgCoreLink" class="dropdown-item" href="#">SQL PostgreSQL core</a></li>
|
||||||
<li><a id="openDemoSqlReplayCandidatesLink" class="dropdown-item" href="#">SQL replay candidates</a></li>
|
<li><a id="openDemoSqlReplayCandidatesLink" class="dropdown-item" href="#">SQL replay candidates</a></li>
|
||||||
<li><hr class="dropdown-divider"></li>
|
<li>
|
||||||
<li><h6 class="dropdown-header">Exécution Devnet</h6></li>
|
<hr class="dropdown-divider">
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<h6 class="dropdown-header">Exécution Devnet</h6>
|
||||||
|
</li>
|
||||||
<li><a id="openDemoExecutionSolanaCoreLink" class="dropdown-item" href="#">Solana Core</a></li>
|
<li><a id="openDemoExecutionSolanaCoreLink" class="dropdown-item" href="#">Solana Core</a></li>
|
||||||
<li><a id="openDemoExecutionSplLink" class="dropdown-item" href="#">SPL</a></li>
|
<li><a id="openDemoExecutionSplLink" class="dropdown-item" href="#">SPL</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -48,11 +67,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main class="app-main">
|
<main class="app-main">
|
||||||
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
<div class="osb-scrollable pt-1 pb-4" data-simplebar>
|
||||||
<div class="container py-4">
|
<div class="container-fluid px-4 py-4">
|
||||||
<div class="row g-4 justify-content-center">
|
<div class="row g-4 justify-content-center">
|
||||||
<div class="col-12 col-xl-10">
|
<div class="col-12">
|
||||||
<div class="card shadow-sm border-0">
|
<div class="card shadow-sm border-0">
|
||||||
<div class="card-body text-start">
|
<div class="card-body text-start">
|
||||||
<h1 class="h3 card-title mb-3">README du projet</h1>
|
<h1 class="h3 card-title mb-3">README du projet</h1>
|
||||||
@@ -67,6 +87,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<footer class="app-footer bg-dark text-light">
|
<footer class="app-footer bg-dark text-light">
|
||||||
<div class="container h-100 d-flex align-items-center">
|
<div class="container h-100 d-flex align-items-center">
|
||||||
<div class="row flex-grow-1 align-items-center">
|
<div class="row flex-grow-1 align-items-center">
|
||||||
@@ -76,4 +97,5 @@
|
|||||||
</footer>
|
</footer>
|
||||||
<script type="module" src="ts/main.ts" defer></script>
|
<script type="module" src="ts/main.ts" defer></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
|
||||||
|
</html>
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
<!-- file: kb-app-demo-desktop/frontend/splash.html -->
|
<!-- file: kb-app-demo-desktop/frontend/splash.html -->
|
||||||
<!-- version: 2 -->
|
<!-- version: 3 -->
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||||
<title>Chargement — Khadhroony Bot3</title>
|
<link rel="stylesheet" href="sass/splash.scss">
|
||||||
<link rel="stylesheet" href="sass/splash.scss" />
|
<title>Khadhroony Bot3 — Chargement</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="splash-container" style="opacity: 0;">
|
<div id="splash-container" style="opacity: 0;">
|
||||||
<img id="splash-image" src="imgs/splash.png" alt="Chargement de Khadhroony Bot3" />
|
<img id="splash-image" src="imgs/splash.png" alt="Chargement de Khadhroony Bot3">
|
||||||
<div id="app-name">Khadhroony</div>
|
<div id="app-name">Khadhroony</div>
|
||||||
<div id="debug-info" aria-live="polite"></div>
|
<div id="debug-info" aria-live="polite"></div>
|
||||||
<div id="messages-container" aria-live="polite"></div>
|
<div id="messages-container" aria-live="polite"></div>
|
||||||
@@ -20,4 +20,4 @@
|
|||||||
<script type="module" src="ts/splash.ts" defer></script>
|
<script type="module" src="ts/splash.ts" defer></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: kb-app-demo-desktop/frontend/ts/demo_backfill.ts
|
// file: kb-app-demo-desktop/frontend/ts/demo_backfill.ts
|
||||||
// version: 6
|
// version: 7
|
||||||
|
|
||||||
import * as bootstrap from "bootstrap";
|
import * as bootstrap from "bootstrap";
|
||||||
import "simplebar";
|
import "simplebar";
|
||||||
@@ -275,9 +275,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
element<HTMLButtonElement>("#cancelBackfillButton").addEventListener("click", () => {
|
element<HTMLButtonElement>("#cancelBackfillButton").addEventListener("click", () => {
|
||||||
void cancelBackfill();
|
void cancelBackfill();
|
||||||
});
|
});
|
||||||
element<HTMLButtonElement>("#clearBackfillLogButton").addEventListener("click", () => {
|
element<HTMLTextAreaElement>("#backfillLogOutput").addEventListener("app-log-clear", () => {
|
||||||
logLines.length = 0;
|
logLines.length = 0;
|
||||||
element<HTMLTextAreaElement>("#backfillLogOutput").value = "";
|
|
||||||
});
|
});
|
||||||
void listen<DemoBackfillProgressPayload>("demo-backfill-progress", event => {
|
void listen<DemoBackfillProgressPayload>("demo-backfill-progress", event => {
|
||||||
appendLog(event.payload);
|
appendLog(event.payload);
|
||||||
@@ -288,10 +287,6 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
frontendError("kb-app-demo-desktop.frontend.backfill", `Options loading failed: ${message}`);
|
frontendError("kb-app-demo-desktop.frontend.backfill", `Options loading failed: ${message}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
document.querySelector<HTMLButtonElement>("#copyBackfillLogButton")?.addEventListener("click", async () => {
|
|
||||||
const value = document.querySelector<HTMLTextAreaElement>("#backfillLogOutput")?.value ?? "";
|
|
||||||
await copyText(value);
|
|
||||||
});
|
|
||||||
document.querySelector<HTMLButtonElement>("#copyBackfillSummaryButton")?.addEventListener("click", async () => {
|
document.querySelector<HTMLButtonElement>("#copyBackfillSummaryButton")?.addEventListener("click", async () => {
|
||||||
const value = document.querySelector("#backfillSummaryOutput andypf-json-viewer")?.getAttribute("data") ?? "";
|
const value = document.querySelector("#backfillSummaryOutput andypf-json-viewer")?.getAttribute("data") ?? "";
|
||||||
await copyText(value);
|
await copyText(value);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: kb-app-demo-desktop/frontend/ts/demo_core_extraction.ts
|
// file: kb-app-demo-desktop/frontend/ts/demo_core_extraction.ts
|
||||||
// version: 4
|
// version: 5
|
||||||
|
|
||||||
import * as bootstrap from "bootstrap";
|
import * as bootstrap from "bootstrap";
|
||||||
import "simplebar";
|
import "simplebar";
|
||||||
@@ -170,9 +170,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
element<HTMLButtonElement>("#cancelCoreExtractionButton").addEventListener("click", () => {
|
element<HTMLButtonElement>("#cancelCoreExtractionButton").addEventListener("click", () => {
|
||||||
void cancelCoreExtraction();
|
void cancelCoreExtraction();
|
||||||
});
|
});
|
||||||
element<HTMLButtonElement>("#clearCoreExtractionLogButton").addEventListener("click", () => {
|
element<HTMLTextAreaElement>("#coreExtractionLogOutput").addEventListener("app-log-clear", () => {
|
||||||
logLines.length = 0;
|
logLines.length = 0;
|
||||||
element<HTMLTextAreaElement>("#coreExtractionLogOutput").value = "";
|
|
||||||
});
|
});
|
||||||
void listen<DemoCoreExtractionProgressPayload>("demo-core-extraction-progress", event => {
|
void listen<DemoCoreExtractionProgressPayload>("demo-core-extraction-progress", event => {
|
||||||
appendLog(event.payload);
|
appendLog(event.payload);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: kb-app-demo-desktop/frontend/ts/demo_execution_solana_core.ts
|
// file: kb-app-demo-desktop/frontend/ts/demo_execution_solana_core.ts
|
||||||
// version: 6
|
// version: 7
|
||||||
|
|
||||||
import * as bootstrap from "bootstrap";
|
import * as bootstrap from "bootstrap";
|
||||||
import "simplebar";
|
import "simplebar";
|
||||||
@@ -28,4 +28,4 @@ function buildRequest(submit:boolean):DemoExecutionSolanaCoreRequest { const rec
|
|||||||
function displaySummary(summary:DemoExecutionSolanaCoreSummaryPayload):void { element<HTMLTextAreaElement>("#executionSummaryOutput").value=JSON.stringify(summary,null,2); element<HTMLTextAreaElement>("#executionPlanOutput").value=summary.planJson; element<HTMLTextAreaElement>("#executionSimulationOutput").value=summary.simulationJson; element<HTMLTextAreaElement>("#executionDiagnosticsOutput").value=summary.diagnosticsJson; }
|
function displaySummary(summary:DemoExecutionSolanaCoreSummaryPayload):void { element<HTMLTextAreaElement>("#executionSummaryOutput").value=JSON.stringify(summary,null,2); element<HTMLTextAreaElement>("#executionPlanOutput").value=summary.planJson; element<HTMLTextAreaElement>("#executionSimulationOutput").value=summary.simulationJson; element<HTMLTextAreaElement>("#executionDiagnosticsOutput").value=summary.diagnosticsJson; }
|
||||||
async function execute(submit:boolean):Promise<void>{if(running){return;}try{const request=buildRequest(submit);if(submit&&!request.operatorConfirmed){frontendWarn("kb-app-demo-desktop.frontend.demo_execution_solana_core","Submission blocked: operator confirmation missing");return;}setRunning(true);const summary=await invoke<DemoExecutionSolanaCoreSummaryPayload>("demo_execution_solana_core_execute",{request});displaySummary(summary);}catch(caughtError){const message=caughtError instanceof Error?caughtError.message:String(caughtError);frontendError("kb-app-demo-desktop.frontend.demo_execution_solana_core",`Execution failed: ${message}`);}finally{setRunning(false);}}
|
async function execute(submit:boolean):Promise<void>{if(running){return;}try{const request=buildRequest(submit);if(submit&&!request.operatorConfirmed){frontendWarn("kb-app-demo-desktop.frontend.demo_execution_solana_core","Submission blocked: operator confirmation missing");return;}setRunning(true);const summary=await invoke<DemoExecutionSolanaCoreSummaryPayload>("demo_execution_solana_core_execute",{request});displaySummary(summary);}catch(caughtError){const message=caughtError instanceof Error?caughtError.message:String(caughtError);frontendError("kb-app-demo-desktop.frontend.demo_execution_solana_core",`Execution failed: ${message}`);}finally{setRunning(false);}}
|
||||||
async function loadOptions():Promise<void>{const options=await invoke<DemoExecutionSolanaCoreOptionsPayload>("demo_execution_solana_core_options");profileOptions=options.profiles;const select=element<HTMLSelectElement>("#executionProfileSelect");select.replaceChildren();for(const profile of profileOptions){const option=document.createElement("option");option.value=profile.name;option.textContent=profile.name;option.selected=profile.name===options.defaultProfileName;select.append(option);}element<HTMLInputElement>("#executionLamportsInput").value=String(options.defaultTransferLamports);updateProfileHelp();setRunning(options.running);}
|
async function loadOptions():Promise<void>{const options=await invoke<DemoExecutionSolanaCoreOptionsPayload>("demo_execution_solana_core_options");profileOptions=options.profiles;const select=element<HTMLSelectElement>("#executionProfileSelect");select.replaceChildren();for(const profile of profileOptions){const option=document.createElement("option");option.value=profile.name;option.textContent=profile.name;option.selected=profile.name===options.defaultProfileName;select.append(option);}element<HTMLInputElement>("#executionLamportsInput").value=String(options.defaultTransferLamports);updateProfileHelp();setRunning(options.running);}
|
||||||
document.addEventListener("DOMContentLoaded",async()=>{installFrontendConsoleBridge("kb-app-demo-desktop.frontend.demo_execution_solana_core");frontendDebug("kb-app-demo-desktop.frontend.demo_execution_solana_core","Solana Core execution window loaded");await listen<DemoExecutionSolanaCoreProgressPayload>("demo-execution-solana-core-progress",event=>appendLog(event.payload));element<HTMLSelectElement>("#executionProfileSelect").addEventListener("change",updateProfileHelp);element<HTMLButtonElement>("#generateRecipientButton").addEventListener("click",async()=>{const payload=await invoke<DemoExecutionSolanaCoreGeneratedRecipientPayload>("demo_execution_solana_core_generate_recipient");element<HTMLInputElement>("#executionRecipientInput").value=payload.publicKey;});element<HTMLButtonElement>("#simulateExecutionButton").addEventListener("click",()=>void execute(false));element<HTMLButtonElement>("#submitExecutionButton").addEventListener("click",()=>void execute(true));element<HTMLButtonElement>("#cancelExecutionButton").addEventListener("click",()=>void invoke("demo_execution_solana_core_cancel"));element<HTMLButtonElement>("#clearExecutionLogButton").addEventListener("click",()=>{logLines.length=0;element<HTMLTextAreaElement>("#executionLogOutput").value="";});try{await loadOptions();}catch(caughtError){const message=caughtError instanceof Error?caughtError.message:String(caughtError);frontendError("kb-app-demo-desktop.frontend.demo_execution_solana_core",`Options loading failed: ${message}`);}});
|
document.addEventListener("DOMContentLoaded",async()=>{installFrontendConsoleBridge("kb-app-demo-desktop.frontend.demo_execution_solana_core");frontendDebug("kb-app-demo-desktop.frontend.demo_execution_solana_core","Solana Core execution window loaded");await listen<DemoExecutionSolanaCoreProgressPayload>("demo-execution-solana-core-progress",event=>appendLog(event.payload));element<HTMLSelectElement>("#executionProfileSelect").addEventListener("change",updateProfileHelp);element<HTMLButtonElement>("#generateRecipientButton").addEventListener("click",async()=>{const payload=await invoke<DemoExecutionSolanaCoreGeneratedRecipientPayload>("demo_execution_solana_core_generate_recipient");element<HTMLInputElement>("#executionRecipientInput").value=payload.publicKey;});element<HTMLButtonElement>("#simulateExecutionButton").addEventListener("click",()=>void execute(false));element<HTMLButtonElement>("#submitExecutionButton").addEventListener("click",()=>void execute(true));element<HTMLButtonElement>("#cancelExecutionButton").addEventListener("click",()=>void invoke("demo_execution_solana_core_cancel"));element<HTMLTextAreaElement>("#executionLogOutput").addEventListener("app-log-clear",()=>{logLines.length=0;});try{await loadOptions();}catch(caughtError){const message=caughtError instanceof Error?caughtError.message:String(caughtError);frontendError("kb-app-demo-desktop.frontend.demo_execution_solana_core",`Options loading failed: ${message}`);}});
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: kb-app-demo-desktop/frontend/ts/demo_execution_spl.ts
|
// file: kb-app-demo-desktop/frontend/ts/demo_execution_spl.ts
|
||||||
// version: 2
|
// version: 3
|
||||||
|
|
||||||
import * as bootstrap from "bootstrap";
|
import * as bootstrap from "bootstrap";
|
||||||
import "simplebar";
|
import "simplebar";
|
||||||
@@ -866,9 +866,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
element<HTMLButtonElement>("#cancelExecutionButton").addEventListener("click", () => {
|
element<HTMLButtonElement>("#cancelExecutionButton").addEventListener("click", () => {
|
||||||
void cancelExecution();
|
void cancelExecution();
|
||||||
});
|
});
|
||||||
element<HTMLButtonElement>("#clearExecutionLogButton").addEventListener("click", () => {
|
element<HTMLTextAreaElement>("#executionLogOutput").addEventListener("app-log-clear", () => {
|
||||||
logLines.length = 0;
|
logLines.length = 0;
|
||||||
element<HTMLTextAreaElement>("#executionLogOutput").value = "";
|
|
||||||
});
|
});
|
||||||
void listen<DemoExecutionSolanaCoreProgressPayload>("demo-execution-solana-core-progress", event => {
|
void listen<DemoExecutionSolanaCoreProgressPayload>("demo-execution-solana-core-progress", event => {
|
||||||
appendLog(event.payload);
|
appendLog(event.payload);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: kb-app-demo-desktop/frontend/ts/frontend_log.ts
|
// file: kb-app-demo-desktop/frontend/ts/frontend_log.ts
|
||||||
// version: 2
|
// version: 3
|
||||||
|
|
||||||
//! Frontend logging helpers that preserve explicit tracing targets.
|
//! Frontend logging helpers that preserve explicit tracing targets.
|
||||||
|
|
||||||
@@ -153,6 +153,7 @@ function upgradeLogOutputs(): void {
|
|||||||
clearButton.textContent = "Effacer";
|
clearButton.textContent = "Effacer";
|
||||||
clearButton.addEventListener("click", () => {
|
clearButton.addEventListener("click", () => {
|
||||||
textarea.value = "";
|
textarea.value = "";
|
||||||
|
textarea.dispatchEvent(new CustomEvent("app-log-clear"));
|
||||||
});
|
});
|
||||||
toolbar.append(copyButton, clearButton);
|
toolbar.append(copyButton, clearButton);
|
||||||
textarea.insertAdjacentElement("beforebegin", toolbar);
|
textarea.insertAdjacentElement("beforebegin", toolbar);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: kb-app-demo-desktop/src/app_state.rs
|
// file: kb-app-demo-desktop/src/app_state.rs
|
||||||
// version: 8
|
// version: 9
|
||||||
|
|
||||||
//! Shared Tauri application state and startup initialization.
|
//! Shared Tauri application state and startup initialization.
|
||||||
|
|
||||||
@@ -28,9 +28,12 @@ pub(crate) struct AppState {
|
|||||||
impl crate::AppState {
|
impl crate::AppState {
|
||||||
/// Initializes configuration, logging and shared runtime state.
|
/// Initializes configuration, logging and shared runtime state.
|
||||||
pub(crate) fn initialize() -> kb_core::Result<crate::AppState> {
|
pub(crate) fn initialize() -> kb_core::Result<crate::AppState> {
|
||||||
load_workspace_dotenv();
|
|
||||||
let config_path = resolve_config_path();
|
let config_path = resolve_config_path();
|
||||||
let app_config = match kb_config::read_config_json_file(&config_path) {
|
let workspace_root = crate::workspace_root_dir();
|
||||||
|
let app_config = match kb_config::read_config_json_file_with_environment(
|
||||||
|
&config_path,
|
||||||
|
&workspace_root,
|
||||||
|
) {
|
||||||
std::result::Result::Ok(config) => config,
|
std::result::Result::Ok(config) => config,
|
||||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
};
|
};
|
||||||
@@ -180,23 +183,6 @@ impl crate::AppState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_workspace_dotenv() {
|
|
||||||
let workspace_path = crate::workspace_root_dir().join(".env");
|
|
||||||
load_dotenv_path(&workspace_path);
|
|
||||||
let desktop_path = crate::workspace_root_dir().join("kb-app-demo-desktop/.env");
|
|
||||||
load_dotenv_path(&desktop_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_dotenv_path(path: &std::path::Path) {
|
|
||||||
let result = dotenvy::from_path(path);
|
|
||||||
if let std::result::Result::Err(error) = result {
|
|
||||||
if matches!(error, dotenvy::Error::Io(ref io_error) if io_error.kind() == std::io::ErrorKind::NotFound) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
eprintln!("cannot load {}: {error}", path.display());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn convert_logging_config(config: &kb_config::LoggingConfig) -> kb_logging::LoggingConfig {
|
fn convert_logging_config(config: &kb_config::LoggingConfig) -> kb_logging::LoggingConfig {
|
||||||
let mut targets = std::vec::Vec::<kb_logging::LogTargetConfig>::new();
|
let mut targets = std::vec::Vec::<kb_logging::LogTargetConfig>::new();
|
||||||
for target in &config.targets {
|
for target in &config.targets {
|
||||||
|
|||||||
@@ -65,8 +65,8 @@ pub(crate) fn open_sql_demo_window(
|
|||||||
tauri::WebviewUrl::App(html_path.into()),
|
tauri::WebviewUrl::App(html_path.into()),
|
||||||
)
|
)
|
||||||
.title(title)
|
.title(title)
|
||||||
.inner_size(1220.0, 780.0)
|
.inner_size(1500.0, 960.0)
|
||||||
.min_inner_size(920.0, 560.0)
|
.min_inner_size(1024.0, 768.0)
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.visible(true);
|
.visible(true);
|
||||||
let build_result = builder.build();
|
let build_result = builder.build();
|
||||||
|
|||||||
@@ -243,9 +243,9 @@ fn open_demo_core_extraction_window(
|
|||||||
"demo_core_extraction",
|
"demo_core_extraction",
|
||||||
tauri::WebviewUrl::App("demo_core_extraction.html".into()),
|
tauri::WebviewUrl::App("demo_core_extraction.html".into()),
|
||||||
)
|
)
|
||||||
.title("Khadhroony Bot3 - Extraction canonical vers core")
|
.title("Extraction canonical vers core")
|
||||||
.inner_size(1280.0, 860.0)
|
.inner_size(1500.0, 960.0)
|
||||||
.min_inner_size(960.0, 620.0)
|
.min_inner_size(1024.0, 768.0)
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.visible(true)
|
.visible(true)
|
||||||
.build();
|
.build();
|
||||||
@@ -354,9 +354,9 @@ fn open_demo_decode_replay_window(
|
|||||||
"demo_decode_replay",
|
"demo_decode_replay",
|
||||||
tauri::WebviewUrl::App("demo_decode_replay.html".into()),
|
tauri::WebviewUrl::App("demo_decode_replay.html".into()),
|
||||||
)
|
)
|
||||||
.title("Khadhroony Bot3 - Décodage et matérialisation")
|
.title("Décodage et matérialisation")
|
||||||
.inner_size(1320.0, 900.0)
|
.inner_size(1500.0, 960.0)
|
||||||
.min_inner_size(980.0, 660.0)
|
.min_inner_size(1024.0, 768.0)
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.visible(true)
|
.visible(true)
|
||||||
.build();
|
.build();
|
||||||
@@ -669,9 +669,9 @@ fn open_demo_config_window(
|
|||||||
"demo_config",
|
"demo_config",
|
||||||
tauri::WebviewUrl::App("demo_config.html".into()),
|
tauri::WebviewUrl::App("demo_config.html".into()),
|
||||||
)
|
)
|
||||||
.title("Khadhroony Bot3 - Configuration")
|
.title("Configuration")
|
||||||
.inner_size(1280.0, 820.0)
|
.inner_size(1500.0, 960.0)
|
||||||
.min_inner_size(960.0, 640.0);
|
.min_inner_size(1024.0, 768.0);
|
||||||
let window = match builder.build() {
|
let window = match builder.build() {
|
||||||
std::result::Result::Ok(value) => value,
|
std::result::Result::Ok(value) => value,
|
||||||
std::result::Result::Err(error) => {
|
std::result::Result::Err(error) => {
|
||||||
@@ -734,9 +734,9 @@ fn open_demo_backfill_window(
|
|||||||
"demo_backfill",
|
"demo_backfill",
|
||||||
tauri::WebviewUrl::App("demo_backfill.html".into()),
|
tauri::WebviewUrl::App("demo_backfill.html".into()),
|
||||||
)
|
)
|
||||||
.title("Khadhroony Bot3 - Backfill HTTP")
|
.title("Backfill HTTP")
|
||||||
.inner_size(1280.0, 860.0)
|
.inner_size(1500.0, 960.0)
|
||||||
.min_inner_size(960.0, 620.0)
|
.min_inner_size(1024.0, 768.0)
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.visible(true)
|
.visible(true)
|
||||||
.build();
|
.build();
|
||||||
@@ -849,9 +849,9 @@ fn open_demo_http_window(
|
|||||||
"demo_http",
|
"demo_http",
|
||||||
tauri::WebviewUrl::App("demo_http.html".into()),
|
tauri::WebviewUrl::App("demo_http.html".into()),
|
||||||
)
|
)
|
||||||
.title("Khadhroony Bot3 - HTTP JSON-RPC")
|
.title("HTTP JSON-RPC")
|
||||||
.inner_size(1280.0, 860.0)
|
.inner_size(1500.0, 960.0)
|
||||||
.min_inner_size(960.0, 620.0)
|
.min_inner_size(1024.0, 768.0)
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.visible(true)
|
.visible(true)
|
||||||
.build();
|
.build();
|
||||||
@@ -912,9 +912,9 @@ fn open_demo_ws_window(
|
|||||||
"demo_ws",
|
"demo_ws",
|
||||||
tauri::WebviewUrl::App("demo_ws.html".into()),
|
tauri::WebviewUrl::App("demo_ws.html".into()),
|
||||||
)
|
)
|
||||||
.title("Khadhroony Bot3 - WebSocket standard")
|
.title("WebSocket standard")
|
||||||
.inner_size(1200.0, 760.0)
|
.inner_size(1500.0, 960.0)
|
||||||
.min_inner_size(920.0, 560.0)
|
.min_inner_size(1024.0, 768.0)
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.visible(true)
|
.visible(true)
|
||||||
.build();
|
.build();
|
||||||
@@ -1011,7 +1011,7 @@ fn open_demo_sql_diag_window(
|
|||||||
app_handle,
|
app_handle,
|
||||||
"demo_sql_diag",
|
"demo_sql_diag",
|
||||||
"demo_sql_diag.html",
|
"demo_sql_diag.html",
|
||||||
"Khadhroony Bot3 - SQL diagnostics",
|
"SQL diagnostics",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1061,7 +1061,7 @@ fn open_demo_sql_pg_raw_window(
|
|||||||
app_handle,
|
app_handle,
|
||||||
"demo_sql_pg_raw",
|
"demo_sql_pg_raw",
|
||||||
"demo_sql_pg_raw.html",
|
"demo_sql_pg_raw.html",
|
||||||
"Khadhroony Bot3 - PostgreSQL canonical acquisition",
|
"PostgreSQL canonical acquisition",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1098,7 +1098,7 @@ fn open_demo_sql_pg_core_window(
|
|||||||
app_handle,
|
app_handle,
|
||||||
"demo_sql_pg_core",
|
"demo_sql_pg_core",
|
||||||
"demo_sql_pg_core.html",
|
"demo_sql_pg_core.html",
|
||||||
"Khadhroony Bot3 - PostgreSQL core store",
|
"PostgreSQL core store",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1135,7 +1135,7 @@ fn open_demo_sql_replay_candidates_window(
|
|||||||
app_handle,
|
app_handle,
|
||||||
"demo_sql_replay_candidates",
|
"demo_sql_replay_candidates",
|
||||||
"demo_sql_replay_candidates.html",
|
"demo_sql_replay_candidates.html",
|
||||||
"Khadhroony Bot3 - SQL replay candidates",
|
"SQL replay candidates",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1358,9 +1358,9 @@ fn open_demo_execution_solana_core_window(
|
|||||||
"demo_execution_solana_core",
|
"demo_execution_solana_core",
|
||||||
tauri::WebviewUrl::App("demo_execution_solana_core.html".into()),
|
tauri::WebviewUrl::App("demo_execution_solana_core.html".into()),
|
||||||
)
|
)
|
||||||
.title("Khadhroony Bot3 - Exécution Solana Devnet")
|
.title("Exécution Solana Devnet")
|
||||||
.inner_size(1360.0, 920.0)
|
.inner_size(1500.0, 960.0)
|
||||||
.min_inner_size(1040.0, 700.0)
|
.min_inner_size(1024.0, 768.0)
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.visible(true)
|
.visible(true)
|
||||||
.build();
|
.build();
|
||||||
@@ -1650,9 +1650,9 @@ fn open_demo_execution_spl_window(
|
|||||||
"demo_execution_spl",
|
"demo_execution_spl",
|
||||||
tauri::WebviewUrl::App("demo_execution_spl.html".into()),
|
tauri::WebviewUrl::App("demo_execution_spl.html".into()),
|
||||||
)
|
)
|
||||||
.title("Khadhroony Bot3 - Exécution SPL Devnet")
|
.title("Exécution SPL Devnet")
|
||||||
.inner_size(1500.0, 960.0)
|
.inner_size(1500.0, 960.0)
|
||||||
.min_inner_size(1120.0, 720.0)
|
.min_inner_size(1024.0, 768.0)
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.visible(true)
|
.visible(true)
|
||||||
.build();
|
.build();
|
||||||
|
|||||||
@@ -27,10 +27,10 @@
|
|||||||
"label": "main",
|
"label": "main",
|
||||||
"url": "main.html",
|
"url": "main.html",
|
||||||
"title": "Khadhroony Bot3",
|
"title": "Khadhroony Bot3",
|
||||||
"width": 1200,
|
"width": 1500,
|
||||||
"height": 768,
|
"height": 960,
|
||||||
"minWidth": 800,
|
"minWidth": 1024,
|
||||||
"minHeight": 600,
|
"minHeight": 768,
|
||||||
"center": true,
|
"center": true,
|
||||||
"visible": false
|
"visible": false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# file: kb-config/Cargo.toml
|
# file: kb-config/Cargo.toml
|
||||||
# version: 2
|
# version: 3
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "kb-config"
|
name = "kb-config"
|
||||||
@@ -9,6 +9,7 @@ license.workspace = true
|
|||||||
publish.workspace = true
|
publish.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
dotenvy.workspace = true
|
||||||
kb-core = { path = "../kb-core" }
|
kb-core = { path = "../kb-core" }
|
||||||
jsonschema.workspace = true
|
jsonschema.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
|
|||||||
@@ -66,3 +66,14 @@ Les structures exposées à Tauri utilisent `TS` avec un chemin `export_to` expl
|
|||||||
cargo test export_bindings -p kb-config
|
cargo test export_bindings -p kb-config
|
||||||
cargo test -p kb-config settings::tests::
|
cargo test -p kb-config settings::tests::
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Résolution de l'environnement
|
||||||
|
|
||||||
|
`kb-config` est l'unique propriétaire du chargement des fichiers `.env` utilisés par la configuration. La priorité est déterministe :
|
||||||
|
|
||||||
|
1. variables déjà présentes dans l'environnement du processus ;
|
||||||
|
2. fichier indiqué par `KB_ENV_FILE`, sinon `.env` à la racine du workspace ;
|
||||||
|
3. fallback `${NOM:-valeur}` déclaré dans le JSON ;
|
||||||
|
4. conservation de `${NOM}` lorsqu'une valeur requise reste absente, afin que les consommateurs optionnels puissent échouer seulement à l'utilisation.
|
||||||
|
|
||||||
|
Les crates métier ne chargent pas elles-mêmes de fichier `.env`.
|
||||||
|
|||||||
98
kb-config/src/environment.rs
Normal file
98
kb-config/src/environment.rs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
// file: kb-config/src/environment.rs
|
||||||
|
// version: 1
|
||||||
|
|
||||||
|
//! Environment-file loading and configuration placeholder resolution.
|
||||||
|
|
||||||
|
/// Result of loading one optional workspace environment file.
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub struct EnvironmentLoadReport {
|
||||||
|
/// Explicit or default environment file that was loaded.
|
||||||
|
pub loaded_path: std::option::Option<std::path::PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Loads the selected environment file without overriding process variables.
|
||||||
|
///
|
||||||
|
/// Resolution order is: existing process environment, selected `.env`, then
|
||||||
|
/// fallback text declared with `${NAME:-fallback}` placeholders.
|
||||||
|
pub fn load_workspace_environment(
|
||||||
|
workspace_root: &std::path::Path,
|
||||||
|
) -> kb_core::Result<EnvironmentLoadReport> {
|
||||||
|
let explicit_path = std::env::var("KB_ENV_FILE").ok();
|
||||||
|
let selected_path = match explicit_path {
|
||||||
|
std::option::Option::Some(path) if !path.trim().is_empty() => {
|
||||||
|
let candidate = std::path::PathBuf::from(path);
|
||||||
|
if candidate.is_absolute() { candidate } else { workspace_root.join(candidate) }
|
||||||
|
},
|
||||||
|
_ => workspace_root.join(".env"),
|
||||||
|
};
|
||||||
|
if !selected_path.exists() {
|
||||||
|
return std::result::Result::Ok(EnvironmentLoadReport { loaded_path: None });
|
||||||
|
}
|
||||||
|
match dotenvy::from_path(&selected_path) {
|
||||||
|
std::result::Result::Ok(()) => {
|
||||||
|
return std::result::Result::Ok(EnvironmentLoadReport {
|
||||||
|
loaded_path: std::option::Option::Some(selected_path),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
std::result::Result::Err(error) => {
|
||||||
|
return std::result::Result::Err(kb_core::Error::new(
|
||||||
|
"config_env_file_load_failed",
|
||||||
|
format!("{}: {error}", selected_path.display()),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolves `${NAME}` and `${NAME:-fallback}` placeholders in arbitrary text.
|
||||||
|
/// Missing variables without fallbacks are preserved for lazy consumers.
|
||||||
|
pub fn resolve_environment_placeholders(raw: &str) -> std::string::String {
|
||||||
|
let mut output = std::string::String::with_capacity(raw.len());
|
||||||
|
let bytes = raw.as_bytes();
|
||||||
|
let mut index = 0_usize;
|
||||||
|
while index < bytes.len() {
|
||||||
|
if bytes[index] == b'$' && index + 1 < bytes.len() && bytes[index + 1] == b'{' {
|
||||||
|
let start = index;
|
||||||
|
let mut end = index + 2;
|
||||||
|
while end < bytes.len() && bytes[end] != b'}' {
|
||||||
|
end += 1;
|
||||||
|
}
|
||||||
|
if end < bytes.len() {
|
||||||
|
let expression = &raw[index + 2..end];
|
||||||
|
let (name, fallback) = match expression.split_once(":-") {
|
||||||
|
std::option::Option::Some((name, fallback)) => {
|
||||||
|
(name, std::option::Option::Some(fallback))
|
||||||
|
},
|
||||||
|
std::option::Option::None => (expression, std::option::Option::None),
|
||||||
|
};
|
||||||
|
let resolved =
|
||||||
|
std::env::var(name).ok().or_else(|| fallback.map(|value| value.to_string()));
|
||||||
|
match resolved {
|
||||||
|
std::option::Option::Some(value) => output.push_str(&value),
|
||||||
|
std::option::Option::None => output.push_str(&raw[start..=end]),
|
||||||
|
}
|
||||||
|
index = end + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output.push(bytes[index] as char);
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn fallback_is_used_when_variable_is_absent() {
|
||||||
|
let resolved =
|
||||||
|
super::resolve_environment_placeholders("${KB_CONFIG_TEST_MISSING:-fallback}");
|
||||||
|
assert_eq!(resolved, "fallback");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unresolved_required_placeholder_is_preserved() {
|
||||||
|
let resolved =
|
||||||
|
super::resolve_environment_placeholders("prefix-${KB_CONFIG_TEST_MISSING}-suffix");
|
||||||
|
assert_eq!(resolved, "prefix-${KB_CONFIG_TEST_MISSING}-suffix");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,20 @@
|
|||||||
// file: kb-config/src/lib.rs
|
// file: kb-config/src/lib.rs
|
||||||
// version: 3
|
// version: 4
|
||||||
|
|
||||||
//! Khadhroony Bot3 workspace configuration contract and loading helpers.
|
//! Khadhroony Bot3 workspace configuration contract and loading helpers.
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
#![deny(unreachable_pub)]
|
#![deny(unreachable_pub)]
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
|
|
||||||
|
mod environment;
|
||||||
mod settings;
|
mod settings;
|
||||||
|
|
||||||
|
/// Exposes the environment loading report.
|
||||||
|
pub use self::environment::EnvironmentLoadReport;
|
||||||
|
/// Exposes workspace environment-file loading.
|
||||||
|
pub use self::environment::load_workspace_environment;
|
||||||
|
/// Exposes environment placeholder resolution.
|
||||||
|
pub use self::environment::resolve_environment_placeholders;
|
||||||
/// Exposes the account listener configuration type.
|
/// Exposes the account listener configuration type.
|
||||||
pub use self::settings::AccountListenerConfig;
|
pub use self::settings::AccountListenerConfig;
|
||||||
/// Exposes the root application configuration type.
|
/// Exposes the root application configuration type.
|
||||||
@@ -60,6 +67,8 @@ pub use self::settings::config_json_schema_value;
|
|||||||
pub use self::settings::parse_config_json;
|
pub use self::settings::parse_config_json;
|
||||||
/// Exposes the configuration loader from a filesystem path.
|
/// Exposes the configuration loader from a filesystem path.
|
||||||
pub use self::settings::read_config_json_file;
|
pub use self::settings::read_config_json_file;
|
||||||
|
/// Exposes configuration loading with workspace environment resolution.
|
||||||
|
pub use self::settings::read_config_json_file_with_environment;
|
||||||
/// Exposes the compact JSON serializer for configuration values.
|
/// Exposes the compact JSON serializer for configuration values.
|
||||||
pub use self::settings::serialize_config_json;
|
pub use self::settings::serialize_config_json;
|
||||||
/// Exposes the pretty JSON serializer for configuration values.
|
/// Exposes the pretty JSON serializer for configuration values.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: kb-config/src/settings.rs
|
// file: kb-config/src/settings.rs
|
||||||
// version: 14
|
// version: 15
|
||||||
|
|
||||||
//! Typed configuration models shared by applications and workers.
|
//! Typed configuration models shared by applications and workers.
|
||||||
|
|
||||||
@@ -525,6 +525,28 @@ pub fn read_config_json_file(path: &std::path::Path) -> kb_core::Result<AppConfi
|
|||||||
return parse_config_json(&raw_json);
|
return parse_config_json(&raw_json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Loads the workspace environment, resolves placeholders and parses one configuration file.
|
||||||
|
pub fn read_config_json_file_with_environment(
|
||||||
|
path: &std::path::Path,
|
||||||
|
workspace_root: &std::path::Path,
|
||||||
|
) -> kb_core::Result<AppConfig> {
|
||||||
|
match crate::load_workspace_environment(workspace_root) {
|
||||||
|
std::result::Result::Ok(_) => (),
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
}
|
||||||
|
let raw_json = match std::fs::read_to_string(path) {
|
||||||
|
std::result::Result::Ok(content) => content,
|
||||||
|
std::result::Result::Err(error) => {
|
||||||
|
return std::result::Result::Err(kb_core::Error::new(
|
||||||
|
"config_file_read_failed",
|
||||||
|
error.to_string(),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let resolved = crate::resolve_environment_placeholders(&raw_json);
|
||||||
|
return parse_config_json(&resolved);
|
||||||
|
}
|
||||||
|
|
||||||
/// Serializes a configuration value to compact JSON.
|
/// Serializes a configuration value to compact JSON.
|
||||||
pub fn serialize_config_json(config: &AppConfig) -> kb_core::Result<std::string::String> {
|
pub fn serialize_config_json(config: &AppConfig) -> kb_core::Result<std::string::String> {
|
||||||
match validate_config(config) {
|
match validate_config(config) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# file: kb-pipeline-demo-scenarios/Cargo.toml
|
# file: kb-pipeline-demo-scenarios/Cargo.toml
|
||||||
# version: 1
|
# version: 2
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "kb-pipeline-demo-scenarios"
|
name = "kb-pipeline-demo-scenarios"
|
||||||
|
|||||||
4
kb-pipeline-demo-scenarios/README.md
Normal file
4
kb-pipeline-demo-scenarios/README.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
## Environnement des scénarios
|
||||||
|
|
||||||
|
Les exécutables et tests opt-in peuvent appeler `initialize_demo_scenario_environment(workspace_root)` avant de lire leurs variables. Cette fonction délègue à `kb-config` et applique la même priorité que l'application desktop. La crate ne dépend pas directement de `dotenvy`.
|
||||||
11
kb-pipeline-demo-scenarios/src/environment.rs
Normal file
11
kb-pipeline-demo-scenarios/src/environment.rs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// file: kb-pipeline-demo-scenarios/src/environment.rs
|
||||||
|
// version: 1
|
||||||
|
|
||||||
|
//! Environment initialization for opt-in demonstration scenarios.
|
||||||
|
|
||||||
|
/// Loads the workspace `.env` selected by `kb-config`.
|
||||||
|
pub fn initialize_demo_scenario_environment(
|
||||||
|
workspace_root: &std::path::Path,
|
||||||
|
) -> kb_core::Result<kb_config::EnvironmentLoadReport> {
|
||||||
|
return kb_config::load_workspace_environment(workspace_root);
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: kb-pipeline-demo-scenarios/src/lib.rs
|
// file: kb-pipeline-demo-scenarios/src/lib.rs
|
||||||
// version: 1
|
// version: 2
|
||||||
|
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
#![deny(unreachable_pub)]
|
#![deny(unreachable_pub)]
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
//! Reusable demonstration and Devnet validation scenarios built on `kb-pipeline`.
|
//! Reusable demonstration and Devnet validation scenarios built on `kb-pipeline`.
|
||||||
|
|
||||||
mod constants;
|
mod constants;
|
||||||
|
mod environment;
|
||||||
mod solana_ata_execution;
|
mod solana_ata_execution;
|
||||||
mod solana_execution;
|
mod solana_execution;
|
||||||
mod solana_memo_execution;
|
mod solana_memo_execution;
|
||||||
@@ -17,6 +18,8 @@ mod solana_token2022_validation;
|
|||||||
mod solana_token_execution;
|
mod solana_token_execution;
|
||||||
mod solana_token_lifecycle;
|
mod solana_token_lifecycle;
|
||||||
|
|
||||||
|
/// Loads the workspace environment for opt-in demo and Devnet scenarios.
|
||||||
|
pub use self::environment::initialize_demo_scenario_environment;
|
||||||
/// Complete request for one Devnet Associated Token Account execution.
|
/// Complete request for one Devnet Associated Token Account execution.
|
||||||
pub use self::solana_ata_execution::DevnetSplAssociatedTokenAccountExecutionRequest;
|
pub use self::solana_ata_execution::DevnetSplAssociatedTokenAccountExecutionRequest;
|
||||||
/// Complete result of one Devnet Associated Token Account execution.
|
/// Complete result of one Devnet Associated Token Account execution.
|
||||||
|
|||||||
BIN
mainnet_research_logs.v0.1.0-pre.055-001.zip
Normal file
BIN
mainnet_research_logs.v0.1.0-pre.055-001.zip
Normal file
Binary file not shown.
@@ -0,0 +1,761 @@
|
|||||||
|
# Prompt de reprise — clôture migration `khadhroony-bot3`
|
||||||
|
|
||||||
|
## 1. Mission
|
||||||
|
|
||||||
|
Poursuivre et clôturer la migration de `khadhroony-bot2` vers `khadhroony-bot3`.
|
||||||
|
|
||||||
|
Objectif fonctionnel intermédiaire :
|
||||||
|
|
||||||
|
- revenir d’abord à un niveau de couverture équivalent à `0.4.6` de Bot2 ;
|
||||||
|
- terminer ensuite le travail Metaplex Token Metadata commencé mais non achevé dans `0.4.7` de Bot2 ;
|
||||||
|
- seulement après cela, finaliser Clippy/Tauri, la documentation et le passage de Bot3 à `0.4.7`.
|
||||||
|
|
||||||
|
Ne pas déclarer la migration terminée avant validation complète des critères de clôture.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Revalidation initiale obligatoire des règles
|
||||||
|
|
||||||
|
Avant toute modification de code :
|
||||||
|
|
||||||
|
1. relire intégralement :
|
||||||
|
- `RULES.md`
|
||||||
|
- `RUST_RULES.md`
|
||||||
|
- `README.md`
|
||||||
|
- `ROADMAP.md`
|
||||||
|
- `CHANGELOG.md`
|
||||||
|
- le présent prompt ;
|
||||||
|
2. comparer les règles Bot2 encore applicables avec les règles Bot3 ;
|
||||||
|
3. vérifier qu’aucune règle de migration récente n’est absente ou contradictoire ;
|
||||||
|
4. vérifier en particulier :
|
||||||
|
- conventions de noms ;
|
||||||
|
- façades `kb-lib` et `kb-store` ;
|
||||||
|
- ordre des imports et réexports ;
|
||||||
|
- interdiction de `unsafe`, `unwrap`, `expect`, `panic`, `anyhow`, `thiserror` ;
|
||||||
|
- règles Tauri ;
|
||||||
|
- conventions TS-RS ;
|
||||||
|
- conventions de logging ;
|
||||||
|
- règles d’archives delta ;
|
||||||
|
- politique de versionnement ;
|
||||||
|
5. corriger les documents de règles avant le code si une divergence est détectée ;
|
||||||
|
6. lancer immédiatement :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo fmt --all
|
||||||
|
python3 scripts/audit_rust_workspace_rules.py
|
||||||
|
```
|
||||||
|
|
||||||
|
L’objectif est d’éviter de refaire plusieurs fois les mêmes corrections structurelles plus tard.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Architecture consolidée
|
||||||
|
|
||||||
|
Crates principales :
|
||||||
|
|
||||||
|
```text
|
||||||
|
kb-config
|
||||||
|
kb-core
|
||||||
|
kb-lib
|
||||||
|
kb-logging
|
||||||
|
kb-onchain-transport
|
||||||
|
kb-pipeline
|
||||||
|
kb-pipeline-demo-scenarios
|
||||||
|
kb-program-ids
|
||||||
|
kb-store
|
||||||
|
kb-wallet
|
||||||
|
kb-app-demo-desktop
|
||||||
|
```
|
||||||
|
|
||||||
|
Règles :
|
||||||
|
|
||||||
|
- `kb-store` remplace `kb_store_core` et `kb_store_pg`.
|
||||||
|
- Modèles, décodeurs, matérialiseurs et exécuteurs sont sous `kb-lib`.
|
||||||
|
- Les modules Rust Token-2022 utilisent `token2022`, jamais `token_2022`.
|
||||||
|
- Les variables externes historiques comme `TOKEN_2022_*` peuvent rester si elles constituent un contrat opératoire.
|
||||||
|
- Les fenêtres dynamiques vont dans `capabilities/default.json` et `vite.config.ts`.
|
||||||
|
- Elles ne vont pas dans `tauri.conf.json`, sauf `splash` et `main`.
|
||||||
|
- Toutes les fenêtres doivent avoir la permission de logging/tracing.
|
||||||
|
- Livrer des ZIP delta, sans `Cargo.lock` ni SHA256.
|
||||||
|
- Les correctifs utilisent `delta-fix-XXX`, avec reprise à `fix-001` pour chaque prerelease.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. État déjà atteint
|
||||||
|
|
||||||
|
Fenêtres migrées / non testées completement :
|
||||||
|
|
||||||
|
- splash ;
|
||||||
|
- main ;
|
||||||
|
- configuration ;
|
||||||
|
- HTTP JSON-RPC ;
|
||||||
|
- WebSocket ;
|
||||||
|
- backfill HTTP ;
|
||||||
|
- SQL diagnostics ;
|
||||||
|
- PostgreSQL raw ;
|
||||||
|
- PostgreSQL core ;
|
||||||
|
- SQL replay candidates ;
|
||||||
|
- extraction core ;
|
||||||
|
- decode replay / matérialisation ;
|
||||||
|
- exécution Solana Core ;
|
||||||
|
- exécution SPL ;
|
||||||
|
- SPL ATA ;
|
||||||
|
- SPL Token classique ;
|
||||||
|
- SPL Token-2022.
|
||||||
|
|
||||||
|
Dépendances déjà présentes :
|
||||||
|
|
||||||
|
```text
|
||||||
|
kb-lib
|
||||||
|
kb-program-ids
|
||||||
|
kb-pipeline-demo-scenarios
|
||||||
|
kb-store
|
||||||
|
kb-wallet
|
||||||
|
```
|
||||||
|
|
||||||
|
Le `.env` est désormais chargé par `kb-config`.
|
||||||
|
|
||||||
|
Ordre de résolution attendu :
|
||||||
|
|
||||||
|
1. environnement du processus ;
|
||||||
|
2. fichier indiqué par `KB_ENV_FILE` ;
|
||||||
|
3. sinon `.env` à la racine du workspace ;
|
||||||
|
4. fallback `${VARIABLE:-valeur}` ;
|
||||||
|
5. absence non fatale pour les services optionnels jusqu’à leur utilisation.
|
||||||
|
|
||||||
|
`HELIUS_API_KEY` fonctionne depuis `.env`.
|
||||||
|
|
||||||
|
Décodeur Metaplex enregistré sous :
|
||||||
|
|
||||||
|
```text
|
||||||
|
metadata_metaplex_token_metadata
|
||||||
|
```
|
||||||
|
|
||||||
|
Program ID :
|
||||||
|
|
||||||
|
```text
|
||||||
|
metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s
|
||||||
|
```
|
||||||
|
|
||||||
|
L’IDL Metaplex Token Metadata est déjà présent dans `idl`. Ne pas le retélécharger.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Contrôles rapides et prise en main du code
|
||||||
|
|
||||||
|
### 5.1 Audit TS-RS
|
||||||
|
|
||||||
|
Auditer uniquement les `.rs` :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find kb-config kb-lib kb-app-demo-desktop -type f -name '*.rs' -print0 |
|
||||||
|
xargs -0 grep -n 'export_to'
|
||||||
|
```
|
||||||
|
|
||||||
|
Chemins attendus :
|
||||||
|
|
||||||
|
```text
|
||||||
|
../frontend/ts/bindings/kb_config/...
|
||||||
|
../frontend/ts/bindings/kb_lib/...
|
||||||
|
../frontend/ts/bindings/kb_app_demo_desktop/...
|
||||||
|
```
|
||||||
|
|
||||||
|
Supprimer les chemins historiques :
|
||||||
|
|
||||||
|
```text
|
||||||
|
kb_executor_*
|
||||||
|
kb_decoder_*
|
||||||
|
kb_materializer_*
|
||||||
|
kb_model
|
||||||
|
kb_store_pg
|
||||||
|
kb_store_core
|
||||||
|
kb_lib_executor_*
|
||||||
|
kb_executor_spl_token_2022
|
||||||
|
```
|
||||||
|
|
||||||
|
Vérifier que les tests TS-RS régénèrent les fichiers attendus.
|
||||||
|
|
||||||
|
### 5.2 Audit des anciens chemins Bot2
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find kb-app-demo-desktop -type f -name '*.rs' -print0 |
|
||||||
|
xargs -0 grep -nE 'kb_store_pg|kb_store_core|kb_model|kb_decoder_|kb_materializer_|kb_executor_|token_2022'
|
||||||
|
```
|
||||||
|
|
||||||
|
Toute occurrence doit être justifiée ou supprimée.
|
||||||
|
|
||||||
|
### 5.3 Audit rapide HTML Copier/Effacer
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find kb-app-demo-desktop/frontend -type f -name '*.html' -print0 |
|
||||||
|
xargs -0 grep -nE 'Copier|Effacer'
|
||||||
|
```
|
||||||
|
|
||||||
|
Vérifier :
|
||||||
|
|
||||||
|
- exactement un bouton Copier ;
|
||||||
|
- exactement un bouton Effacer ;
|
||||||
|
- aucun doublon entre HTML statique et helper TypeScript ;
|
||||||
|
- journaux globaux hors accordéon.
|
||||||
|
|
||||||
|
### 5.4 Menu principal
|
||||||
|
|
||||||
|
Ordre attendu :
|
||||||
|
|
||||||
|
1. Configuration
|
||||||
|
2. Transport et collecte
|
||||||
|
3. Pipeline
|
||||||
|
4. SQL
|
||||||
|
5. Exécution
|
||||||
|
|
||||||
|
Vérifier labels, séparateurs, entrées mortes et fenêtres oubliées.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Corrections UI rapides
|
||||||
|
|
||||||
|
### `demo_http`
|
||||||
|
|
||||||
|
Le bloc `Résultat` ne doit pas utiliser `@andypf/json-viewer`.
|
||||||
|
|
||||||
|
À faire :
|
||||||
|
|
||||||
|
- remettre un `<textarea readonly>` ;
|
||||||
|
- hauteur fixe ;
|
||||||
|
- scroll interne ;
|
||||||
|
- exactement un bouton Copier ;
|
||||||
|
- exactement un bouton Effacer ;
|
||||||
|
- l’effacement doit vider aussi le buffer TypeScript.
|
||||||
|
|
||||||
|
### `demo_ws`
|
||||||
|
|
||||||
|
Le bloc `Messages` doit être un affichage texte/log.
|
||||||
|
|
||||||
|
À faire :
|
||||||
|
|
||||||
|
- utiliser un `<textarea>` ou composant log ;
|
||||||
|
- hauteur fixe et scroll interne ;
|
||||||
|
- exactement une paire Copier/Effacer ;
|
||||||
|
- conserver les messages si la fenêtre est fermée puis rouverte tant que la session reste active.
|
||||||
|
|
||||||
|
### Journaux généraux
|
||||||
|
|
||||||
|
Vérifier au minimum :
|
||||||
|
|
||||||
|
- Backfill HTTP ;
|
||||||
|
- Extraction core ;
|
||||||
|
- Exécution Solana Core ;
|
||||||
|
- Exécution SPL ;
|
||||||
|
- Decode replay ;
|
||||||
|
- HTTP ;
|
||||||
|
- WebSocket.
|
||||||
|
|
||||||
|
Règle générale :
|
||||||
|
|
||||||
|
- paramètres dans les accordéons ;
|
||||||
|
- journaux et résultats globaux sous les accordéons ;
|
||||||
|
- hauteur fixe ;
|
||||||
|
- scroll interne ;
|
||||||
|
- boutons toujours accessibles.
|
||||||
|
|
||||||
|
### JSON viewers
|
||||||
|
|
||||||
|
- `@andypf/json-viewer` uniquement pour du JSON structuré ;
|
||||||
|
- `<textarea>` pour texte brut, logs, messages, sorties non JSON et diagnostics concaténés ;
|
||||||
|
- hauteur fixe et scroll interne pour tous les viewers JSON.
|
||||||
|
|
||||||
|
### Fenêtres SQL
|
||||||
|
|
||||||
|
Sauf Replay Candidates :
|
||||||
|
|
||||||
|
- contenu sur toute la largeur ;
|
||||||
|
- pas de split en deux colonnes ;
|
||||||
|
- table sur toute la largeur ;
|
||||||
|
- éviter le scroll horizontal global ;
|
||||||
|
- wrapper responsive uniquement autour de la table ;
|
||||||
|
- vérifier les balises HTML ;
|
||||||
|
- vérifier boutons, tabs et liens.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. `.env` et configuration
|
||||||
|
|
||||||
|
`kb-config` doit rester seul responsable de :
|
||||||
|
|
||||||
|
- recherche du `.env` ;
|
||||||
|
- chargement sans écraser l’environnement du processus ;
|
||||||
|
- `${VAR}` ;
|
||||||
|
- `${VAR:-fallback}` ;
|
||||||
|
- diagnostics sans secrets ;
|
||||||
|
- tests ;
|
||||||
|
- documentation publique.
|
||||||
|
|
||||||
|
Les crates métier ne doivent pas charger `.env`.
|
||||||
|
|
||||||
|
`kb-pipeline-demo-scenarios` peut appeler un point d’initialisation commun, mais ne doit pas dépendre directement de `dotenvy`.
|
||||||
|
|
||||||
|
Backlog futur :
|
||||||
|
|
||||||
|
- étudier la résolution du chemin/URL de base de données côté `kb-store`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Logging
|
||||||
|
|
||||||
|
La console doit rester active pour :
|
||||||
|
|
||||||
|
- `local_devnet` ;
|
||||||
|
- `mainnet_research` ;
|
||||||
|
- `mainnet`.
|
||||||
|
|
||||||
|
Supprimer les routes Bot2 obsolètes.
|
||||||
|
|
||||||
|
Cibles consolidées attendues :
|
||||||
|
|
||||||
|
```text
|
||||||
|
kb-lib.decoder.*
|
||||||
|
kb-lib.executor.*
|
||||||
|
kb-lib.materializer.*
|
||||||
|
kb-store
|
||||||
|
kb-config
|
||||||
|
kb-logging
|
||||||
|
kb-onchain-transport
|
||||||
|
kb-pipeline
|
||||||
|
kb-wallet
|
||||||
|
kb-app-demo-desktop
|
||||||
|
```
|
||||||
|
|
||||||
|
Ne pas recréer les anciens dossiers de crates supprimées.
|
||||||
|
|
||||||
|
Backlog non bloquant :
|
||||||
|
|
||||||
|
- séparer ultérieurement les logs `kb-store` entre `core` et `postgres`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Options SPL et variables Token-2022
|
||||||
|
|
||||||
|
Auditer :
|
||||||
|
|
||||||
|
```text
|
||||||
|
kb-app-demo-desktop/frontend/demo_execution_spl.html
|
||||||
|
kb-app-demo-desktop/src/tauri.rs
|
||||||
|
```
|
||||||
|
|
||||||
|
Vérifier que chaque option HTML correspond à un scénario réellement supporté.
|
||||||
|
|
||||||
|
Éliminer les valeurs internes `token_2022` au profit de `token2022`, sauf contrat externe explicite.
|
||||||
|
|
||||||
|
Pour chaque variable `TOKEN_2022_*`, décider :
|
||||||
|
|
||||||
|
- compatibilité externe à conserver ;
|
||||||
|
- déplacement éventuel vers configuration ;
|
||||||
|
- remplacement futur par structure typée ;
|
||||||
|
- usage limité aux scénarios de démonstration.
|
||||||
|
|
||||||
|
Documenter la décision.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. WebSocket
|
||||||
|
|
||||||
|
Comportement obligatoire :
|
||||||
|
|
||||||
|
- aucun pool WebSocket au démarrage ;
|
||||||
|
- création paresseuse au premier accès à `demo_ws` ;
|
||||||
|
- pool conservé dans `AppState` ;
|
||||||
|
- session conservée si la fenêtre est fermée ;
|
||||||
|
- état récupéré à la réouverture ;
|
||||||
|
- fermeture seulement par :
|
||||||
|
- commande explicite ;
|
||||||
|
- timeout ;
|
||||||
|
- arrêt global de l’application.
|
||||||
|
|
||||||
|
La fermeture de `demo_ws` ne doit pas appeler la déconnexion globale.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. Initialisation PostgreSQL au lancement
|
||||||
|
|
||||||
|
L’initialisation PostgreSQL doit être faite au lancement de `kb-app-demo-desktop`, comme dans Bot2.
|
||||||
|
|
||||||
|
Ordre attendu :
|
||||||
|
|
||||||
|
1. environnement ;
|
||||||
|
2. configuration ;
|
||||||
|
3. logging ;
|
||||||
|
4. pool HTTP ;
|
||||||
|
5. connexion PostgreSQL ;
|
||||||
|
6. vérification/initialisation du schéma ;
|
||||||
|
7. rapport des tables ;
|
||||||
|
8. ouverture de `main` ;
|
||||||
|
9. destruction du splash.
|
||||||
|
|
||||||
|
Fonctions existantes à raccorder :
|
||||||
|
|
||||||
|
```text
|
||||||
|
initialize_postgres_schema_for_startup
|
||||||
|
emit_sql_startup_table_report
|
||||||
|
emit_sql_startup_error
|
||||||
|
emit_sql_startup_splash
|
||||||
|
```
|
||||||
|
|
||||||
|
### Splashscreen
|
||||||
|
|
||||||
|
Problème observé : seuls les messages du haut sont visibles.
|
||||||
|
|
||||||
|
À corriger :
|
||||||
|
|
||||||
|
- zone de messages scrollable ;
|
||||||
|
- hauteur adaptée ;
|
||||||
|
- dernier message visible ;
|
||||||
|
- progression lisible ;
|
||||||
|
- ne pas afficher d’initialisation WebSocket ;
|
||||||
|
- afficher :
|
||||||
|
- connexion PostgreSQL ;
|
||||||
|
- schéma vérifié ou initialisé ;
|
||||||
|
- nombre de tables ;
|
||||||
|
- tables manquantes éventuelles ;
|
||||||
|
- statut final.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. PostgreSQL — purge des données dérivées
|
||||||
|
|
||||||
|
Objectif : conserver uniquement les données raw, puis tout reconstruire par replay.
|
||||||
|
|
||||||
|
Ne pas supprimer :
|
||||||
|
|
||||||
|
- transactions raw ;
|
||||||
|
- signatures raw ;
|
||||||
|
- payloads RPC raw ;
|
||||||
|
- données nécessaires à l’extraction et au replay.
|
||||||
|
|
||||||
|
Purger les tables dérivées liées notamment à :
|
||||||
|
|
||||||
|
- core extraction ;
|
||||||
|
- decoded events ;
|
||||||
|
- observations ;
|
||||||
|
- coverage ;
|
||||||
|
- diagnostics ;
|
||||||
|
- replay state dérivé ;
|
||||||
|
- annotations ;
|
||||||
|
- materialized events ;
|
||||||
|
- token accounts ;
|
||||||
|
- lifecycle ;
|
||||||
|
- admin ;
|
||||||
|
- fees ;
|
||||||
|
- risk ;
|
||||||
|
- compliance ;
|
||||||
|
- staking ;
|
||||||
|
- autres projections générées.
|
||||||
|
|
||||||
|
Avant purge :
|
||||||
|
|
||||||
|
1. inventorier les tables via `kb-store` ;
|
||||||
|
2. distinguer précisément raw et dérivé ;
|
||||||
|
3. préparer un script SQL versionné et idempotent ;
|
||||||
|
4. documenter les tables conservées ;
|
||||||
|
5. exécuter dans une transaction ;
|
||||||
|
6. prévoir des vérifications avant/après ;
|
||||||
|
7. ne rien supprimer si le périmètre est ambigu.
|
||||||
|
|
||||||
|
Après purge :
|
||||||
|
|
||||||
|
1. extraction core ;
|
||||||
|
2. replay de tous les décodeurs ;
|
||||||
|
3. matérialisation ;
|
||||||
|
4. validation des compteurs ;
|
||||||
|
5. validation des erreurs ;
|
||||||
|
6. contrôle de reconstruction des tables.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. Retour au niveau fonctionnel `0.4.6`
|
||||||
|
|
||||||
|
Avant de poursuivre Metaplex, valider que Bot3 couvre correctement tout ce qui était fonctionnel dans Bot2 `0.4.6` :
|
||||||
|
|
||||||
|
- Solana Core ;
|
||||||
|
- SPL Memo ;
|
||||||
|
- SPL Token classique ;
|
||||||
|
- SPL ATA ;
|
||||||
|
- SPL Token-2022 ;
|
||||||
|
- ElGamal Registry ;
|
||||||
|
- backfill ;
|
||||||
|
- extraction core ;
|
||||||
|
- replay ;
|
||||||
|
- matérialisation ;
|
||||||
|
- exécution supportée ;
|
||||||
|
- validations devnet déjà existantes ;
|
||||||
|
- transport HTTP et WebSocket ;
|
||||||
|
- PostgreSQL ;
|
||||||
|
- logging ;
|
||||||
|
- configuration.
|
||||||
|
|
||||||
|
Cette étape doit être explicitement considérée comme un jalon de migration.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 14. Inventaire des IDL
|
||||||
|
|
||||||
|
Créer :
|
||||||
|
|
||||||
|
```text
|
||||||
|
docs/IDL_SOURCES.md
|
||||||
|
```
|
||||||
|
|
||||||
|
Pour chaque IDL :
|
||||||
|
|
||||||
|
- protocole ;
|
||||||
|
- program ID ;
|
||||||
|
- lien officiel ;
|
||||||
|
- version ou commit ;
|
||||||
|
- chemin local ;
|
||||||
|
- statut ;
|
||||||
|
- usage ;
|
||||||
|
- notes de compatibilité.
|
||||||
|
|
||||||
|
Ne pas inventer d’IDL lorsqu’il n’en existe pas.
|
||||||
|
|
||||||
|
L’IDL Metaplex Token Metadata existe déjà localement : le référencer, ne pas le retélécharger.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 15. Metaplex Token Metadata — décodage
|
||||||
|
|
||||||
|
Ce bloc vient après le retour au niveau fonctionnel `0.4.6`.
|
||||||
|
|
||||||
|
Des échecs réels ont été observés après backfill Metaplex.
|
||||||
|
|
||||||
|
Cas signalés :
|
||||||
|
|
||||||
|
- `create_metadata_account_v3` ;
|
||||||
|
- `transfer`.
|
||||||
|
|
||||||
|
Cause probable : attentes incorrectes sur les flags signer/writable des metas.
|
||||||
|
|
||||||
|
Travail :
|
||||||
|
|
||||||
|
1. extraire toutes les erreurs Metaplex ;
|
||||||
|
2. regrouper par instruction ;
|
||||||
|
3. comparer runtime, IDL local, builders et interface officielle ;
|
||||||
|
4. corriger la matrice de comptes ;
|
||||||
|
5. distinguer instructions valides, transactions échouées, payloads tronqués, variantes inconnues, comptes optionnels et legacy ;
|
||||||
|
6. ajouter des tests depuis les transactions réelles ;
|
||||||
|
7. relancer le replay ;
|
||||||
|
8. obtenir zéro faux échec de metas.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 16. Exécuteur Metaplex et démos devnet
|
||||||
|
|
||||||
|
Le passage à `0.4.7` exige que l’exécuteur Metaplex Token Metadata soit terminé.
|
||||||
|
|
||||||
|
À compléter :
|
||||||
|
|
||||||
|
- intents typés ;
|
||||||
|
- builders ;
|
||||||
|
- comptes ordonnés ;
|
||||||
|
- signers ;
|
||||||
|
- writable flags ;
|
||||||
|
- variantes supportées ;
|
||||||
|
- politiques de sécurité ;
|
||||||
|
- simulation-first ;
|
||||||
|
- estimation des coûts ;
|
||||||
|
- validation post-exécution ;
|
||||||
|
- tests unitaires ;
|
||||||
|
- comparaison avec builders officiels ;
|
||||||
|
- matrice de couverture.
|
||||||
|
|
||||||
|
Ajouter des scénarios devnet bornés dans `kb-app-demo-desktop` et/ou `kb-pipeline-demo-scenarios`.
|
||||||
|
|
||||||
|
Ils doivent :
|
||||||
|
|
||||||
|
- utiliser uniquement un profil devnet explicite ;
|
||||||
|
- ne jamais exécuter par défaut sur mainnet ;
|
||||||
|
- simuler avant envoi ;
|
||||||
|
- afficher le plan ;
|
||||||
|
- afficher les signers ;
|
||||||
|
- afficher le résultat ;
|
||||||
|
- effectuer un replay post-exécution ;
|
||||||
|
- vérifier décodage et matérialisation ;
|
||||||
|
- afficher les diagnostics.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 17. Clippy et Tauri
|
||||||
|
|
||||||
|
Les erreurs `clippy::question_mark_used` issues des macros async Tauri sont à traiter après tout le fonctionnel, y compris Metaplex.
|
||||||
|
|
||||||
|
Ne pas bloquer le débogage dessus.
|
||||||
|
|
||||||
|
À la fin :
|
||||||
|
|
||||||
|
1. solution locale cohérente ;
|
||||||
|
2. éviter un `allow` global ;
|
||||||
|
3. documenter la contradiction macro/règle ;
|
||||||
|
4. obtenir un Clippy propre ou un écart précisément borné.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 18. Refonte documentaire après migration
|
||||||
|
|
||||||
|
Ne pas commencer la refonte complète avant validation fonctionnelle, y compris Metaplex.
|
||||||
|
|
||||||
|
### Versionnement
|
||||||
|
|
||||||
|
Passer à :
|
||||||
|
|
||||||
|
```text
|
||||||
|
0.4.7
|
||||||
|
```
|
||||||
|
|
||||||
|
uniquement si :
|
||||||
|
|
||||||
|
- niveau fonctionnel `0.4.6` restauré et validé ;
|
||||||
|
- migration validée ;
|
||||||
|
- bugs majeurs corrigés ;
|
||||||
|
- exécuteur Metaplex terminé ;
|
||||||
|
- démos devnet Metaplex présentes ;
|
||||||
|
- replay et matérialisation validés ;
|
||||||
|
- documentation refondue.
|
||||||
|
|
||||||
|
### README
|
||||||
|
|
||||||
|
Les README doivent devenir génériques.
|
||||||
|
|
||||||
|
Ils ne doivent pas :
|
||||||
|
|
||||||
|
- servir de changelog ;
|
||||||
|
- contenir des numéros de version ;
|
||||||
|
- raconter Bot2 → Bot3 ;
|
||||||
|
- décrire les prereleases.
|
||||||
|
|
||||||
|
Ils doivent présenter :
|
||||||
|
|
||||||
|
- objectif ;
|
||||||
|
- rôle architectural ;
|
||||||
|
- dépendances ;
|
||||||
|
- aperçu minimal ;
|
||||||
|
- liens vers la documentation détaillée.
|
||||||
|
|
||||||
|
### `USAGES.md`
|
||||||
|
|
||||||
|
Créer un `USAGES.md` pour chaque crate publique.
|
||||||
|
|
||||||
|
Contenu :
|
||||||
|
|
||||||
|
- APIs publiques ;
|
||||||
|
- types ;
|
||||||
|
- traits ;
|
||||||
|
- fonctions ;
|
||||||
|
- builders ;
|
||||||
|
- exemples ;
|
||||||
|
- invariants ;
|
||||||
|
- erreurs ;
|
||||||
|
- limites ;
|
||||||
|
- intégrations.
|
||||||
|
|
||||||
|
### Roadmap par crate
|
||||||
|
|
||||||
|
Ajouter un roadmap par crate seulement si utile.
|
||||||
|
|
||||||
|
### Continuité du projet
|
||||||
|
|
||||||
|
Après refonte, on ne doit presque plus sentir la transition Bot2 → Bot3.
|
||||||
|
|
||||||
|
Seule une courte note historique éventuelle est acceptable.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 19. Commandes de validation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo fmt --all
|
||||||
|
|
||||||
|
cargo check -p kb-config
|
||||||
|
cargo test -p kb-config
|
||||||
|
|
||||||
|
cargo check -p kb-pipeline-demo-scenarios
|
||||||
|
cargo test -p kb-pipeline-demo-scenarios
|
||||||
|
|
||||||
|
cargo check -p kb-store
|
||||||
|
cargo test -p kb-store
|
||||||
|
|
||||||
|
cargo check -p kb-lib
|
||||||
|
cargo test -p kb-lib
|
||||||
|
|
||||||
|
cargo check -p kb-app-demo-desktop
|
||||||
|
cargo test -p kb-app-demo-desktop
|
||||||
|
|
||||||
|
cargo check --workspace
|
||||||
|
cargo test --workspace
|
||||||
|
|
||||||
|
python3 scripts/audit_rust_workspace_rules.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Runtime :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo tauri dev -c kb-app-demo-desktop/tauri.conf.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Clippy en dernier :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo clippy --all-targets
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 20. Critères de clôture
|
||||||
|
|
||||||
|
- [ ] règles relues et revalidées ;
|
||||||
|
- [ ] toutes les crates compilent ;
|
||||||
|
- [ ] tous les tests workspace passent ;
|
||||||
|
- [ ] audit Rust propre ;
|
||||||
|
- [ ] aucun chemin Bot2 supprimé ;
|
||||||
|
- [ ] audit TS-RS propre ;
|
||||||
|
- [ ] toutes les fenêtres fonctionnent ;
|
||||||
|
- [ ] WebSocket persistant après fermeture de `demo_ws` ;
|
||||||
|
- [ ] `.env` chargé par `kb-config` avec priorité correcte ;
|
||||||
|
- [ ] Helius réellement validé ;
|
||||||
|
- [ ] PostgreSQL initialisé au démarrage ;
|
||||||
|
- [ ] splash PostgreSQL lisible ;
|
||||||
|
- [ ] données dérivées purgées ;
|
||||||
|
- [ ] données dérivées reconstruites par replay ;
|
||||||
|
- [ ] niveau fonctionnel `0.4.6` restauré ;
|
||||||
|
- [ ] bons composants pour JSON et texte ;
|
||||||
|
- [ ] aucun bouton Copier/Effacer dupliqué ;
|
||||||
|
- [ ] journaux généraux hors accordéon ;
|
||||||
|
- [ ] fenêtres SQL correctement dimensionnées ;
|
||||||
|
- [ ] routes de logs obsolètes supprimées ;
|
||||||
|
- [ ] console active ;
|
||||||
|
- [ ] inventaire IDL documenté ;
|
||||||
|
- [ ] aucun faux échec Metaplex sur les metas ;
|
||||||
|
- [ ] exécuteur Metaplex terminé ;
|
||||||
|
- [ ] démos devnet Metaplex validées ;
|
||||||
|
- [ ] Clippy/Tauri finalisés ;
|
||||||
|
- [ ] refonte documentaire terminée ;
|
||||||
|
- [ ] `USAGES.md` présent pour chaque crate publique ;
|
||||||
|
- [ ] passage à `0.4.7` justifié.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 21. Mode de travail
|
||||||
|
|
||||||
|
- Commencer chaque session par la relecture des règles.
|
||||||
|
- Traiter d’abord les contrôles rapides.
|
||||||
|
- Conserver un ordre logique de dépendances.
|
||||||
|
- Revenir au niveau fonctionnel `0.4.6` avant de terminer Metaplex.
|
||||||
|
- Traiter Metaplex avant Clippy/Tauri et la documentation.
|
||||||
|
- Travailler par deltas courts.
|
||||||
|
- Ne jamais réintroduire les anciennes crates Bot2.
|
||||||
|
- Vérifier les APIs réelles avant de porter du code.
|
||||||
|
- Utiliser `kb-store` et `kb-lib`.
|
||||||
|
- Corriger immédiatement les erreurs locales remontées.
|
||||||
|
- Ne pas masquer les erreurs métier par des `allow`.
|
||||||
|
- Maintenir `delta.md`, changelog et documentation de session.
|
||||||
|
- Fournir une archive delta à chaque tranche.
|
||||||
|
- Utiliser `delta-fix-XXX` pour les correctifs.
|
||||||
|
- Ne pas livrer d’archive complète sauf demande explicite.
|
||||||
Reference in New Issue
Block a user