792 lines
35 KiB
Markdown
792 lines
35 KiB
Markdown
<!-- file: docs/DEVNET_EXECUTION_GUIDE.md -->
|
||
<!-- version: 19 -->
|
||
|
||
# Guide d’exécution Devnet
|
||
|
||
## 1. Objet et ordre de validation
|
||
|
||
Ce guide décrit la campagne Devnet de `kb-app-demo-desktop` et `kb-pipeline-demo-scenarios`. Après une modification de nomenclature persistée ou une recréation de la base Devnet, reprendre les scénarios depuis le début dans l’ordre suivant :
|
||
|
||
1. préparation commune et base PostgreSQL propre ;
|
||
2. Solana Core — System Transfer ;
|
||
3. SPL Memo v4 ;
|
||
4. SPL Associated Token Account — mint Token classique ;
|
||
5. SPL Associated Token Account — mint Token-2022 ;
|
||
6. SPL Token classique ;
|
||
7. Token-2022 ;
|
||
8. registre ElGamal.
|
||
|
||
Les commandes réutilisables sont centralisées en section 4. Chaque scénario référence leur identifiant `Cxx` au lieu de les recopier.
|
||
|
||
## 2. Préconditions
|
||
|
||
- `.env` contient `KB_POSTGRES_DEVNET_URL` et les secrets de transport requis ;
|
||
- `KB_POSTGRES_DEVNET_URL`, `KB_POSTGRES_MAINNET_URL` et `KB_POSTGRES_TEST_URL` désignent des bases distinctes ;
|
||
- le profil sélectionné est Devnet et autorise explicitement l’envoi Devnet ;
|
||
- l’envoi Mainnet reste désactivé ;
|
||
- les plafonds de frais, de dépense et de rent sont contrôlés ;
|
||
- la politique reste `simulation-first` ;
|
||
- le wallet temporaire persistant n’est jamais copié dans les logs ou les preuves ;
|
||
- le financement est réalisé par un faucet Web Devnet, pas par `solana airdrop`.
|
||
|
||
Lorsque `database.postgres.auto_initialize_schema` vaut `true`, l’ouverture d’une fenêtre Devnet crée les tables manquantes. Lorsqu’il vaut `false`, le schéma doit être préparé avant l’ouverture.
|
||
|
||
## 3. Organisation des terminaux
|
||
|
||
La campagne utilise deux terminaux distincts. Les variables d’environnement exportées dans un terminal ne sont pas visibles dans l’autre.
|
||
|
||
### Terminal A — application Tauri
|
||
|
||
Ce terminal reste occupé par `cargo tauri dev` pendant toute la campagne. Il affiche les logs Rust, Tauri, Vite, PostgreSQL et RPC.
|
||
|
||
### Terminal B — contrôles CLI et preuves
|
||
|
||
Ce terminal reste disponible pour les commandes Solana, PostgreSQL, balances, confirmations et captures avec `tee`.
|
||
|
||
Les commandes `C01` à `C05` doivent être exécutées dans le terminal B. Le terminal A doit exécuter `T01`, puis rester ouvert. Avant chaque scénario, le terminal B doit définir `KB_DEVNET_SCENARIO` avant d’appeler `C06`.
|
||
|
||
## 4. Commandes communes
|
||
|
||
Les commandes suivantes sont exécutées depuis la racine du workspace dans un terminal interactif. Ne pas utiliser `set -e` ou `set -u` dans ce terminal : une commande de contrôle non satisfaite fermerait la session. `set -o pipefail` est suffisant pour fiabiliser les pipelines vers `tee`.
|
||
|
||
### T01 — Démarrer l’application dans le terminal A
|
||
|
||
Premier lancement du workspace ou après modification des dépendances frontend :
|
||
|
||
```bash
|
||
cd ~/Projects/khadhroony-bot3; command -v cargo; command -v npm; command -v cargo-tauri || cargo install tauri-cli --locked; test -d kb-app-demo-desktop/node_modules || npm --prefix kb-app-demo-desktop i; cargo tauri dev -c kb-app-demo-desktop/tauri.conf.json
|
||
```
|
||
|
||
La commande `npm --prefix kb-app-demo-desktop i -D ...` installe ou réaligne explicitement les dépendances de développement déclarées par l’application. `npm --prefix kb-app-demo-desktop i` reste nécessaire pour les dépendances runtime.
|
||
|
||
Installation ou réalignement conditionnel des dépendances de développement, uniquement après modification de `package.json`, suppression de `node_modules` ou erreur de dépendance frontend :
|
||
|
||
```bash
|
||
npm --prefix kb-app-demo-desktop i -D @tauri-apps/cli @types/bootstrap @types/markdown-it @types/node sass-embedded typescript vite
|
||
```
|
||
|
||
`npm run dev` est lancé automatiquement par Tauri via `beforeDevCommand`; il exécute le script `dev` du `package.json`, actuellement Vite. Il ne faut pas le lancer dans un troisième terminal.
|
||
|
||
La validation frontend de cette campagne est effectuée par `cargo tauri dev -c kb-app-demo-desktop/tauri.conf.json`, qui lance Vite. Ne pas ajouter `npm --prefix kb-app-demo-desktop run build` à la procédure.
|
||
|
||
Lancements suivants, lorsque `cargo-tauri` et `node_modules` sont déjà présents :
|
||
|
||
```bash
|
||
cd ~/Projects/khadhroony-bot3; cargo tauri dev -c kb-app-demo-desktop/tauri.conf.json
|
||
```
|
||
|
||
Attendre avant tout scénario :
|
||
|
||
- le démarrage de Vite ;
|
||
- le lancement du binaire `kb-app-demo-desktop` ;
|
||
- l’ouverture de la fenêtre ;
|
||
- le message PostgreSQL indiquant que les 13 tables sont prêtes ;
|
||
- la résolution correcte du profil `local_devnet`.
|
||
|
||
Ne pas exécuter les commandes `C06` ou `C07` dans ce terminal.
|
||
|
||
### T02 — Arrêter et redémarrer Tauri conditionnellement
|
||
|
||
Redémarrer Tauri après :
|
||
|
||
- recréation du schéma PostgreSQL si l’application était déjà ouverte ;
|
||
- modification de `.env`, de la configuration ou du profil actif ;
|
||
- recompilation liée à une correction de code ;
|
||
- perte de connexion entre Vite et la fenêtre.
|
||
|
||
Arrêter avec `Ctrl+C`, puis relancer `T01`.
|
||
|
||
### C01 — Initialiser l’environnement de validation
|
||
|
||
```bash
|
||
cd ~/Projects/khadhroony-bot3 && set -o pipefail && export KB_DEVNET_PROFILE="local_devnet" && export KB_DEVNET_RPC_URL="https://api.devnet.solana.com" && export KB_DEVNET_VALIDATION_DIR="/tmp/devnet-validation/pre.062-clean" && export KB_DEVNET_WALLET="$PWD/wallets/temporary/local_devnet/local-devnet-operator.json" && mkdir -p "$KB_DEVNET_VALIDATION_DIR" && printf 'Profil : %s\n' "$KB_DEVNET_PROFILE" && printf 'RPC Devnet : %s\n' "$KB_DEVNET_RPC_URL" && printf 'Preuves : %s\n' "$KB_DEVNET_VALIDATION_DIR" && printf 'Wallet : %s\n' "$KB_DEVNET_WALLET";
|
||
```
|
||
|
||
### C02 — Capturer les versions CLI
|
||
|
||
```bash
|
||
command -v solana && command -v solana-keygen && command -v spl-token && { date --iso-8601=seconds; solana --version; solana-keygen --version; spl-token --version; } | tee "$KB_DEVNET_VALIDATION_DIR/00-cli-versions.txt";
|
||
```
|
||
|
||
La première campagne `pre.062` utilisait `solana-cli 4.0.2`, `solana-keygen 4.0.2` et `spl-token-cli 5.5.0`. Une nouvelle campagne doit capturer ses propres versions.
|
||
|
||
### C03 — Vérifier l’identité du réseau
|
||
|
||
```bash
|
||
solana config set --url "$KB_DEVNET_RPC_URL" && { date --iso-8601=seconds; solana config get; solana cluster-version --url "$KB_DEVNET_RPC_URL"; solana genesis-hash --url "$KB_DEVNET_RPC_URL"; solana epoch-info --url "$KB_DEVNET_RPC_URL"; } | tee "$KB_DEVNET_VALIDATION_DIR/01-devnet-network.txt";
|
||
```
|
||
|
||
Le genesis hash Devnet attendu est :
|
||
|
||
```text
|
||
EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG
|
||
```
|
||
|
||
### C04 — Vérifier le wallet opérateur
|
||
|
||
```bash
|
||
test -f "$KB_DEVNET_WALLET" && chmod 600 "$KB_DEVNET_WALLET" && export KB_DEVNET_WALLET_PUBKEY="$(solana-keygen pubkey "$KB_DEVNET_WALLET")" && { date --iso-8601=seconds; printf 'wallet_path=%s\n' "$KB_DEVNET_WALLET"; printf 'wallet_pubkey=%s\n' "$KB_DEVNET_WALLET_PUBKEY"; solana balance "$KB_DEVNET_WALLET_PUBKEY" --url "$KB_DEVNET_RPC_URL" --commitment confirmed; } | tee "$KB_DEVNET_VALIDATION_DIR/02-wallet.txt"
|
||
```
|
||
|
||
### C05 — Recréer la base Devnet
|
||
|
||
Cette commande est destructive. Elle ne doit viser que `KB_POSTGRES_DEVNET_URL`. Elle supprime toutes les données et tous les objets du schéma `public`, puis laisse l’application recréer son schéma lors de l’ouverture d’une fenêtre Devnet.
|
||
|
||
```bash
|
||
test -n "$KB_POSTGRES_DEVNET_URL" && printf '%s\n' "$KB_POSTGRES_DEVNET_URL" && export KB_CONFIRM_DEVNET_DATABASE_RESET="YES_RESET_SOLANA_DEVNET" && test "$KB_CONFIRM_DEVNET_DATABASE_RESET" = "YES_RESET_SOLANA_DEVNET" && psql "$KB_POSTGRES_DEVNET_URL" -v ON_ERROR_STOP=1 -c 'DROP SCHEMA public CASCADE; CREATE SCHEMA public;'
|
||
```
|
||
|
||
Après ouverture d’une fenêtre Devnet, contrôler les tables :
|
||
|
||
```bash
|
||
psql "$KB_POSTGRES_DEVNET_URL" -v ON_ERROR_STOP=1 -c "SELECT schemaname, tablename FROM pg_tables WHERE schemaname = 'public' ORDER BY tablename;" | tee "$KB_DEVNET_VALIDATION_DIR/03-devnet-schema.txt"
|
||
```
|
||
|
||
### C06 — Capturer le solde avant scénario
|
||
|
||
Définir `KB_DEVNET_SCENARIO` avant l’appel.
|
||
|
||
```bash
|
||
test -n "${KB_DEVNET_SCENARIO:-}" && test -n "${KB_DEVNET_WALLET_PUBKEY:-}" && test -n "${KB_DEVNET_RPC_URL:-}" && test -n "${KB_DEVNET_VALIDATION_DIR:-}" && { date --iso-8601=seconds; printf 'scenario=%s\nwallet=%s\n' "$KB_DEVNET_SCENARIO" "$KB_DEVNET_WALLET_PUBKEY"; solana balance "$KB_DEVNET_WALLET_PUBKEY" --url "$KB_DEVNET_RPC_URL" --commitment confirmed; } | tee "$KB_DEVNET_VALIDATION_DIR/${KB_DEVNET_SCENARIO}-wallet-before.txt"
|
||
```
|
||
|
||
### C07 — Confirmer une signature et capturer le solde après scénario
|
||
|
||
Définir `KB_DEVNET_SCENARIO` et `KB_DEVNET_SIGNATURE` avant l’appel.
|
||
|
||
```bash
|
||
test -n "${KB_DEVNET_SCENARIO:-}" && test -n "${KB_DEVNET_SIGNATURE:-}" && test -n "${KB_DEVNET_WALLET_PUBKEY:-}" && test -n "${KB_DEVNET_RPC_URL:-}" && test -n "${KB_DEVNET_VALIDATION_DIR:-}" && { date --iso-8601=seconds; printf 'scenario=%s\nsignature=%s\n' "$KB_DEVNET_SCENARIO" "$KB_DEVNET_SIGNATURE"; solana confirm "$KB_DEVNET_SIGNATURE" --url "$KB_DEVNET_RPC_URL" --commitment finalized --verbose; solana balance "$KB_DEVNET_WALLET_PUBKEY" --url "$KB_DEVNET_RPC_URL" --commitment confirmed; } | tee "$KB_DEVNET_VALIDATION_DIR/${KB_DEVNET_SCENARIO}-confirmation.txt"
|
||
```
|
||
|
||
### C08 — Préparer un mint SPL Token classique pour ATA
|
||
|
||
Cette commande crée uniquement un mint de test persistant. Elle ne crée aucun compte token associé : l’ATA doit être dérivé, simulé et créé par `kb-app-demo-desktop`.
|
||
|
||
L’option `--silent` est obligatoire afin que la phrase de récupération ne soit pas affichée dans le terminal, les captures ou l’historique de validation.
|
||
|
||
La commande est idempotente au niveau du guide : si le compte du mint existe déjà sur Devnet, elle le réutilise.
|
||
|
||
```bash
|
||
export KB_SPL_TOKEN_PROGRAM_ID="TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" && export KB_DEVNET_CLASSIC_MINT_KEYPAIR="$PWD/wallets/temporary/local_devnet/mints/ata-classic-mint.json" && mkdir -p "$(dirname "$KB_DEVNET_CLASSIC_MINT_KEYPAIR")" && { test -f "$KB_DEVNET_CLASSIC_MINT_KEYPAIR" || solana-keygen new --no-bip39-passphrase --force --silent --outfile "$KB_DEVNET_CLASSIC_MINT_KEYPAIR"; }
|
||
```
|
||
|
||
```bash
|
||
export KB_DEVNET_CLASSIC_MINT="$(solana-keygen pubkey "$KB_DEVNET_CLASSIC_MINT_KEYPAIR")" && { solana account "$KB_DEVNET_CLASSIC_MINT" --url "$KB_DEVNET_RPC_URL" --output json >/dev/null 2>&1 || spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_PROGRAM_ID" create-token "$KB_DEVNET_CLASSIC_MINT_KEYPAIR" --decimals 9; } && printf 'classic_mint=%s\n' "$KB_DEVNET_CLASSIC_MINT" | tee "$KB_DEVNET_VALIDATION_DIR/30a-spl-ata-classic-mint.txt"
|
||
```
|
||
|
||
### C09 — Préparer un mint Token-2022 pour ATA
|
||
|
||
Cette commande crée uniquement un mint Token-2022 de test persistant, sans extension supplémentaire. Elle ne crée aucun ATA.
|
||
|
||
```bash
|
||
export KB_SPL_TOKEN_2022_PROGRAM_ID="TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" && export KB_DEVNET_TOKEN_2022_MINT_KEYPAIR="$PWD/wallets/temporary/local_devnet/mints/ata-token-2022-mint.json" && mkdir -p "$(dirname "$KB_DEVNET_TOKEN_2022_MINT_KEYPAIR")" && { test -f "$KB_DEVNET_TOKEN_2022_MINT_KEYPAIR" || solana-keygen new --no-bip39-passphrase --force --silent --outfile "$KB_DEVNET_TOKEN_2022_MINT_KEYPAIR"; }
|
||
```
|
||
|
||
```bash
|
||
export KB_DEVNET_TOKEN_2022_MINT="$(solana-keygen pubkey "$KB_DEVNET_TOKEN_2022_MINT_KEYPAIR")" && { solana account "$KB_DEVNET_TOKEN_2022_MINT" --url "$KB_DEVNET_RPC_URL" --output json >/dev/null 2>&1 || spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_2022_PROGRAM_ID" create-token "$KB_DEVNET_TOKEN_2022_MINT_KEYPAIR" --decimals 9; } && printf 'token_2022_mint=%s\n' "$KB_DEVNET_TOKEN_2022_MINT" | tee "$KB_DEVNET_VALIDATION_DIR/30b-spl-ata-token-2022-mint.txt"
|
||
```
|
||
|
||
### C10 — Préparer les comptes du scénario SPL Token classique
|
||
|
||
La fenêtre actuelle **Décodeur spl_token — TransferChecked** valide uniquement `TransferChecked`. Elle exige :
|
||
|
||
- un mint SPL Token classique ;
|
||
- un compte source appartenant au wallet opérateur et possédant un solde token suffisant ;
|
||
- un compte destination distinct pour le même mint ;
|
||
- l’autorité simple du compte source, qui doit être le wallet opérateur.
|
||
|
||
Cette préparation réutilise le mint créé par `C08` et l’ATA classique créée pendant `S03A`.
|
||
|
||
1. Dériver l’ATA source avec la syntaxe exigée par `spl-token-cli 5.5.0` :
|
||
|
||
```bash
|
||
export KB_DEVNET_CLASSIC_SOURCE_ATA="$(spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_PROGRAM_ID" address --verbose --token "$KB_DEVNET_CLASSIC_MINT" --owner "$KB_DEVNET_WALLET_PUBKEY" | awk -F': ' '/Associated token address/ {print $2}')" && test -n "$KB_DEVNET_CLASSIC_SOURCE_ATA" && printf 'source_ata=%s\n' "$KB_DEVNET_CLASSIC_SOURCE_ATA"
|
||
```
|
||
|
||
2. Préparer un owner destinataire persistant :
|
||
|
||
```bash
|
||
export KB_DEVNET_CLASSIC_RECIPIENT_KEYPAIR="$PWD/wallets/temporary/local_devnet/recipients/spl-token-transfer-recipient.json" && mkdir -p "$(dirname "$KB_DEVNET_CLASSIC_RECIPIENT_KEYPAIR")" && { test -f "$KB_DEVNET_CLASSIC_RECIPIENT_KEYPAIR" || solana-keygen new --no-bip39-passphrase --force --silent --outfile "$KB_DEVNET_CLASSIC_RECIPIENT_KEYPAIR"; } && export KB_DEVNET_CLASSIC_RECIPIENT="$(solana-keygen pubkey "$KB_DEVNET_CLASSIC_RECIPIENT_KEYPAIR")"
|
||
```
|
||
|
||
3. Dériver puis créer l’ATA destination si elle n’existe pas :
|
||
|
||
```bash
|
||
export KB_DEVNET_CLASSIC_DESTINATION_ATA="$(spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_PROGRAM_ID" address --verbose --token "$KB_DEVNET_CLASSIC_MINT" --owner "$KB_DEVNET_CLASSIC_RECIPIENT" | awk -F': ' '/Associated token address/ {print $2}')" && test -n "$KB_DEVNET_CLASSIC_DESTINATION_ATA" && { solana account "$KB_DEVNET_CLASSIC_DESTINATION_ATA" --url "$KB_DEVNET_RPC_URL" --output json >/dev/null 2>&1 || spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_PROGRAM_ID" create-account "$KB_DEVNET_CLASSIC_MINT" --owner "$KB_DEVNET_CLASSIC_RECIPIENT" --fee-payer "$KB_DEVNET_WALLET"; }
|
||
```
|
||
|
||
4. Créditer le compte source. Cette commande ajoute `10` tokens à chaque exécution ; ne la relancer que si le solde source est insuffisant :
|
||
|
||
```bash
|
||
spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_PROGRAM_ID" mint "$KB_DEVNET_CLASSIC_MINT" 10 "$KB_DEVNET_CLASSIC_SOURCE_ATA" --owner "$KB_DEVNET_WALLET" --fee-payer "$KB_DEVNET_WALLET"
|
||
```
|
||
|
||
5. Afficher les comptes par leur adresse. Avec cette version du CLI, utiliser `display` plutôt que `account-info <adresse>`, car l’argument positionnel de `account-info` est interprété comme un mint :
|
||
|
||
```bash
|
||
spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_PROGRAM_ID" display "$KB_DEVNET_CLASSIC_SOURCE_ATA" && spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_PROGRAM_ID" display "$KB_DEVNET_CLASSIC_DESTINATION_ATA"
|
||
```
|
||
|
||
6. Capturer la fixture :
|
||
|
||
```bash
|
||
{ printf 'mint=%s\n' "$KB_DEVNET_CLASSIC_MINT"; printf 'source=%s\n' "$KB_DEVNET_CLASSIC_SOURCE_ATA"; printf 'destination=%s\n' "$KB_DEVNET_CLASSIC_DESTINATION_ATA"; printf 'authority=%s\n' "$KB_DEVNET_WALLET_PUBKEY"; printf 'amount_raw=1000000000\n'; printf 'decimals=9\n'; } | tee "$KB_DEVNET_VALIDATION_DIR/40-spl-token-fixture.txt"
|
||
```
|
||
|
||
La création du compte destination par CLI est acceptable ici : `S03A` et `S03B` ont déjà validé l’executor ATA. `S04` doit isoler et valider l’executor SPL Token `TransferChecked`.
|
||
|
||
### C11 — Créer ou réutiliser la fixture Token-2022
|
||
|
||
Le workspace fournit une commande idempotente qui prépare les comptes publics requis par les huit scénarios Token-2022 :
|
||
|
||
```bash
|
||
cargo run -p kb-pipeline-demo-scenarios --bin kb-pipeline-demo-scenarios-cli -- prepare-token-2022-fixture --rpc-url "$KB_DEVNET_RPC_URL" --wallet "$KB_DEVNET_WALLET" --wallet-dir "$PWD/wallets/temporary/local_devnet" --decimals 9 | tee "$KB_DEVNET_VALIDATION_DIR/50-spl-token-2022-fixture-preparation.json"
|
||
```
|
||
|
||
Lorsque `--rpc-url` et `--wallet` sont omis, la commande utilise respectivement `KB_DEVNET_RPC_URL` et `KB_DEVNET_WALLET`. Lorsque `--wallet-dir` est omis, elle utilise le répertoire parent du wallet.
|
||
|
||
La commande :
|
||
|
||
- crée silencieusement les keypairs manquants avec des permissions `0600` ;
|
||
- crée ou réutilise un mint Token-2022 avec mint authority et freeze authority égales au wallet opérateur ;
|
||
- crée ou réutilise trois comptes Token-2022 distincts : source, destination et compte vide réservé à `CloseAccount` ;
|
||
- crée ou réutilise une pubkey delegate indépendante ;
|
||
- n'affiche jamais les phrases de récupération ni les octets privés ;
|
||
- écrit atomiquement la fixture publique attendue par l'application.
|
||
|
||
Les keypairs et la fixture sont conservés sous :
|
||
|
||
```text
|
||
wallets/temporary/local_devnet/spl_token_2022_validation/
|
||
```
|
||
|
||
La fixture publique est :
|
||
|
||
```text
|
||
wallets/temporary/local_devnet/spl_token_2022_validation/fixture.env
|
||
```
|
||
|
||
Elle définit :
|
||
|
||
```text
|
||
TOKEN_2022_PROGRAM
|
||
TOKEN_2022_MINT
|
||
TOKEN_2022_SOURCE
|
||
TOKEN_2022_DESTINATION
|
||
TOKEN_2022_CLOSE_ACCOUNT
|
||
TOKEN_2022_DELEGATE
|
||
TOKEN_2022_AUTHORITY
|
||
TOKEN_2022_FREEZE_AUTHORITY
|
||
TOKEN_2022_DECIMALS
|
||
TOKEN_2022_MINT_AMOUNT_RAW
|
||
TOKEN_2022_TRANSFER_AMOUNT_RAW
|
||
TOKEN_2022_APPROVE_AMOUNT_RAW
|
||
TOKEN_2022_BURN_AMOUNT_RAW
|
||
KB_DEVNET_WALLET_ADDRESS
|
||
```
|
||
|
||
Vérifier puis charger uniquement les valeurs publiques dans le terminal B :
|
||
|
||
```bash
|
||
export KB_DEVNET_TOKEN_2022_FIXTURE="$PWD/wallets/temporary/local_devnet/spl_token_2022_validation/fixture.env" && test -f "$KB_DEVNET_TOKEN_2022_FIXTURE" && sed -n '/^export [A-Z0-9_]*=/p' "$KB_DEVNET_TOKEN_2022_FIXTURE" | sed 's/=.*$/=<défini>/' | tee "$KB_DEVNET_VALIDATION_DIR/50-spl-token-2022-fixture-keys.txt" && source "$KB_DEVNET_TOKEN_2022_FIXTURE"
|
||
```
|
||
|
||
Afficher le mint et les trois comptes Token-2022 avec le Program ID explicite :
|
||
|
||
```bash
|
||
spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$TOKEN_2022_PROGRAM" display "$TOKEN_2022_MINT" && spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$TOKEN_2022_PROGRAM" display "$TOKEN_2022_SOURCE" && spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$TOKEN_2022_PROGRAM" display "$TOKEN_2022_DESTINATION" && spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$TOKEN_2022_PROGRAM" display "$TOKEN_2022_CLOSE_ACCOUNT"
|
||
```
|
||
|
||
Le compte `TOKEN_2022_CLOSE_ACCOUNT` doit rester vide jusqu'au scénario `CloseAccount`. Ne pas utiliser `account-info <adresse>` dans cette campagne : avec `spl-token-cli 5.5.0`, cette forme peut interpréter l'adresse comme un mint.
|
||
|
||
### C12 — Preuves applicatives communes
|
||
|
||
|
||
|
||
Pour chaque scénario, conserver depuis l’application :
|
||
|
||
- profil et cluster résolus ;
|
||
- paramètres saisis ;
|
||
- `operation_code`, `program_id` et plan préparé ;
|
||
- signers requis et fee payer ;
|
||
- plafond de frais et plafond de dépense ;
|
||
- résultat et logs de simulation ;
|
||
- signature d’envoi ;
|
||
- résultat de confirmation ;
|
||
- insertion canonique ;
|
||
- extraction Core ;
|
||
- Decode replay ciblé ;
|
||
- projections matérialisées ;
|
||
- second replay démontrant l’idempotence ;
|
||
- diagnostics ou écarts observés.
|
||
|
||
Un scénario n’est validé que si le replay ne produit ni échec fonctionnel ni erreur de traitement et si les projections attendues sont présentes et idempotentes.
|
||
|
||
## 5. Préparation initiale de la campagne
|
||
|
||
1. Dans le terminal B, exécuter `C01`, `C02`, `C03` et `C04`.
|
||
2. Dans le terminal B, exécuter `C05` pour repartir d’une base propre.
|
||
3. Dans le terminal A, exécuter `T01`.
|
||
4. Attendre la création des 13 tables et la disponibilité de la fenêtre.
|
||
5. Dans la fenêtre Configuration, vérifier que `local_devnet` utilise la base Devnet.
|
||
6. Dans le terminal B, exécuter le contrôle de tables de `C05`.
|
||
7. Financer la pubkey par un faucet Web Devnet si le solde est insuffisant.
|
||
8. Réexécuter `C04` dans le terminal B après financement.
|
||
9. Avant chaque scénario, définir `KB_DEVNET_SCENARIO` dans le terminal B, puis exécuter `C06`.
|
||
|
||
## 6. Scénario S01 — Solana Core System Transfer
|
||
|
||
### Objectif
|
||
|
||
Valider la chaîne complète : préparation, simulation, envoi, confirmation, stockage canonique, extraction Core et replay.
|
||
|
||
### Procédure
|
||
|
||
1. Définir puis exécuter `C06` :
|
||
|
||
```bash
|
||
export KB_DEVNET_SCENARIO="10-system-transfer"
|
||
```
|
||
|
||
2. Dans la fenêtre **Exécution Devnet — Solana Core** :
|
||
- générer un nouveau destinataire ;
|
||
- conserver sa pubkey ;
|
||
- saisir un montant borné ;
|
||
- vérifier `solana.core.system.transfer` ;
|
||
- simuler ;
|
||
- contrôler frais, spend et signer ;
|
||
- confirmer explicitement l’envoi.
|
||
3. Définir la signature et exécuter `C07`.
|
||
4. Capturer séparément le solde du destinataire :
|
||
|
||
```bash
|
||
export KB_DEVNET_RECIPIENT="COLLER_LE_DESTINATAIRE"
|
||
|
||
solana balance \
|
||
"$KB_DEVNET_RECIPIENT" \
|
||
--url "$KB_DEVNET_RPC_URL" \
|
||
--commitment confirmed \
|
||
| tee "$KB_DEVNET_VALIDATION_DIR/${KB_DEVNET_SCENARIO}-recipient-after.txt"
|
||
```
|
||
|
||
5. Exécuter les contrôles applicatifs `C08` sur la signature.
|
||
|
||
### Contrat d’erreur de l’interface
|
||
|
||
Pour un nouveau destinataire inexistant, le montant doit être au moins égal au minimum de rent exemption indiqué par l’application. Avec la valeur observée de `890880` lamports, une demande de `10000` lamports doit être refusée avant simulation.
|
||
|
||
Ce refus est attendu fonctionnellement, mais l’interface doit afficher l’erreur dans les panneaux de résultat :
|
||
|
||
- `Résumé` doit passer de `idle` à `error` ;
|
||
- `Plan exact` doit afficher l’échec de préparation ou rester explicitement indisponible avec sa cause ;
|
||
- `Simulation exacte` doit indiquer qu’aucune simulation n’a été lancée à cause du préflight ;
|
||
- `Confirmation et replay` doit rester non exécuté, avec une raison explicite.
|
||
|
||
Un message uniquement présent dans le journal est insuffisant. Tant que les panneaux restent à `idle`, ne pas considérer le scénario comme validé et ne pas utiliser « Signer et envoyer ».
|
||
|
||
### Résultat historique de référence
|
||
|
||
La première campagne a validé la signature `3k8BaQJKwSn8r2pYdvfp1Q3VYrPEcDEuUunMFn7NDq1ZqsvryjoGsxeBBNJjc1123RgDCoykp7w9VrtZgsDw4ph3`, au slot `479589279`, avec `890880` lamports transférés, `5000` lamports de frais et `150` compute units. Cette preuve réseau reste historique ; les lignes PostgreSQL doivent être recréées dans la nouvelle base.
|
||
|
||
## 7. Scénario S02 — SPL Memo v4
|
||
|
||
### Objectif
|
||
|
||
Valider l’opération exécutable `spl.memo.add_memo`, l’événement observé `spl.memo.v4.add_memo` et la projection d’annotation.
|
||
|
||
### Procédure
|
||
|
||
1. Définir puis exécuter `C06` :
|
||
|
||
```bash
|
||
export KB_DEVNET_SCENARIO="20-spl-memo-v4"
|
||
```
|
||
|
||
2. Dans la fenêtre **Exécution Devnet — SPL** :
|
||
- sélectionner Memo v4 ;
|
||
- saisir un texte UTF-8 borné ;
|
||
- vérifier le Program ID `Memo4c2pN8afCj432Lb7RMVKi9PbQnnW7ewFFaV3oAH` ;
|
||
- vérifier le wallet signer ;
|
||
- simuler puis confirmer l’envoi.
|
||
3. Définir `KB_DEVNET_SIGNATURE` et exécuter `C07`.
|
||
4. Exécuter `C08` et vérifier précisément :
|
||
- `processor_name = materializer.transaction.annotations` ;
|
||
- `surface_code = spl.memo.v4` ;
|
||
- `event_code = spl.memo.v4.add_memo` ;
|
||
- une seule annotation matérialisée ;
|
||
- second replay ignoré/idempotent.
|
||
|
||
### Résultat historique de référence
|
||
|
||
La première campagne a validé la signature `3uYNASrHibwpnsFWwV2JHAxtnci96RhFYf6zbUSfGMbQQV37gfHizstk7atiHYYQCBm4jhmC6cT3G3CCPCV38Lpx`, au slot `479596483`, avec `5000` lamports de frais et `513` compute units. Après recréation de la base, cette signature peut être réingérée pour tester le replay, mais la campagne propre doit également produire une nouvelle preuve complète.
|
||
|
||
## 8. Scénario S03 — SPL Associated Token Account
|
||
|
||
Le scénario ATA est divisé en deux validations indépendantes. Une ATA dépend du triplet exact :
|
||
|
||
```text
|
||
owner + token_program + mint
|
||
```
|
||
|
||
Un même owner et deux mints appartenant à des Token Programs différents doivent donc produire deux dérivations et deux comptes distincts.
|
||
|
||
### S03A — ATA avec SPL Token classique
|
||
|
||
#### Objectif
|
||
|
||
Valider la dérivation et la création idempotente d’une ATA dont le mint appartient au programme SPL Token classique.
|
||
|
||
#### Préparation dans le terminal B
|
||
|
||
1. Exécuter `C08`.
|
||
2. Définir le scénario et capturer le solde :
|
||
|
||
```bash
|
||
export KB_DEVNET_SCENARIO="30a-spl-ata-classic"
|
||
```
|
||
|
||
3. Exécuter `C06`.
|
||
4. Copier la valeur affichée par :
|
||
|
||
```bash
|
||
printf '%s\n' "$KB_DEVNET_CLASSIC_MINT"
|
||
```
|
||
|
||
#### Procédure dans l’application
|
||
|
||
1. Ouvrir la fenêtre **SPL Associated Token Account**.
|
||
2. Utiliser :
|
||
- owner : wallet opérateur `KB_DEVNET_WALLET_PUBKEY` ;
|
||
- mint : `KB_DEVNET_CLASSIC_MINT` ;
|
||
- token program : SPL Token classique ;
|
||
- payer : wallet opérateur.
|
||
3. Dériver l’ATA et conserver son adresse.
|
||
4. Vérifier que le Program ID sélectionné est `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`.
|
||
5. Simuler `spl.associated_token_account.create_idempotent`.
|
||
6. Contrôler le rent ceiling, le payer, l’owner, le mint, le token program et l’adresse ATA dérivée.
|
||
7. Confirmer explicitement l’envoi.
|
||
8. Définir `KB_DEVNET_SIGNATURE`, puis exécuter `C07`.
|
||
9. Exécuter `C12`.
|
||
10. Réexécuter la création idempotente et vérifier qu’elle ne produit ni fausse création ni duplication des projections.
|
||
|
||
### S03B — ATA avec Token-2022
|
||
|
||
#### Objectif
|
||
|
||
Valider la dérivation et la création idempotente d’une ATA dont le mint appartient au programme Token-2022, puis démontrer qu’elle est distincte de l’ATA classique.
|
||
|
||
#### Préparation dans le terminal B
|
||
|
||
1. Exécuter `C09`.
|
||
2. Définir le scénario et capturer le solde :
|
||
|
||
```bash
|
||
export KB_DEVNET_SCENARIO="30b-spl-ata-token-2022"
|
||
```
|
||
|
||
3. Exécuter `C06`.
|
||
4. Copier la valeur affichée par :
|
||
|
||
```bash
|
||
printf '%s\n' "$KB_DEVNET_TOKEN_2022_MINT"
|
||
```
|
||
|
||
#### Procédure dans l’application
|
||
|
||
1. Utiliser :
|
||
- owner : le même wallet opérateur ;
|
||
- mint : `KB_DEVNET_TOKEN_2022_MINT` ;
|
||
- token program : Token-2022 ;
|
||
- payer : wallet opérateur.
|
||
2. Dériver l’ATA et conserver son adresse.
|
||
3. Vérifier que le Program ID sélectionné est `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`.
|
||
4. Vérifier que l’adresse dérivée diffère de l’ATA classique de S03A.
|
||
5. Simuler puis envoyer `spl.associated_token_account.create_idempotent`.
|
||
6. Définir `KB_DEVNET_SIGNATURE`, puis exécuter `C07`.
|
||
7. Exécuter `C12`.
|
||
8. Rejouer la création idempotente.
|
||
9. Vérifier séparément les faits parent ATA et les éventuels enfants CPI Token-2022, sans duplication.
|
||
|
||
### Critères communs S03A/S03B
|
||
|
||
- le mint existe et son owner on-chain correspond au Token Program choisi ;
|
||
- l’adresse ATA est dérivée avec les graines dans l’ordre canonique `owner`, `token_program`, `mint` ;
|
||
- le compte créé a pour owner le Token Program attendu ;
|
||
- le premier envoi peut créer le compte ;
|
||
- le second envoi idempotent ne crée pas un second compte ;
|
||
- le replay et les projections restent idempotents ;
|
||
- aucune ATA classique n’est confondue avec une ATA Token-2022.
|
||
|
||
## 9. Scénario S04 — SPL Token classique
|
||
|
||
### Portée réellement exposée
|
||
|
||
La fenêtre actuelle expose uniquement :
|
||
|
||
```text
|
||
spl.token.transfer_checked
|
||
```
|
||
|
||
Elle ne permet pas encore d’enchaîner depuis l’interface `InitializeMint`, `MintToChecked`, `Approve`, `Revoke`, `BurnChecked` et `CloseAccount`. Ces opérations restent hors de ce scénario Devnet tant qu’elles ne sont pas exposées par la fenêtre.
|
||
|
||
### Préparation dans le terminal B
|
||
|
||
1. Réutiliser le mint classique de `C08` :
|
||
|
||
```bash
|
||
export KB_SPL_TOKEN_PROGRAM_ID="TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" && export KB_DEVNET_CLASSIC_MINT_KEYPAIR="$PWD/wallets/temporary/local_devnet/mints/ata-classic-mint.json" && export KB_DEVNET_CLASSIC_MINT="$(solana-keygen pubkey "$KB_DEVNET_CLASSIC_MINT_KEYPAIR")"
|
||
```
|
||
|
||
2. Définir le scénario :
|
||
|
||
```bash
|
||
export KB_DEVNET_SCENARIO="40-spl-token"
|
||
```
|
||
|
||
3. Exécuter `C06`.
|
||
4. Exécuter `C10`.
|
||
5. Vérifier les comptes token avant l’opération :
|
||
|
||
```bash
|
||
spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_PROGRAM_ID" display "$KB_DEVNET_CLASSIC_SOURCE_ATA" && spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_PROGRAM_ID" display "$KB_DEVNET_CLASSIC_DESTINATION_ATA"
|
||
```
|
||
|
||
### Valeurs à saisir dans l’application
|
||
|
||
Dans **Décodeur spl_token — TransferChecked** :
|
||
|
||
| Champ | Valeur |
|
||
|--------------------|--------------------------------------------|
|
||
| Compte source | `$KB_DEVNET_CLASSIC_SOURCE_ATA` |
|
||
| Mint | `$KB_DEVNET_CLASSIC_MINT` |
|
||
| Compte destination | `$KB_DEVNET_CLASSIC_DESTINATION_ATA` |
|
||
| Autorité simple | `$KB_DEVNET_WALLET_PUBKEY` |
|
||
| Montant brut exact | `1000000000` pour 1 token avec 9 décimales |
|
||
| Decimals | `9` |
|
||
|
||
Afficher les valeurs à copier :
|
||
|
||
```bash
|
||
printf 'source=%s\nmint=%s\ndestination=%s\nauthority=%s\namount_raw=1000000000\ndecimals=9\n' "$KB_DEVNET_CLASSIC_SOURCE_ATA" "$KB_DEVNET_CLASSIC_MINT" "$KB_DEVNET_CLASSIC_DESTINATION_ATA" "$KB_DEVNET_WALLET_PUBKEY"
|
||
```
|
||
|
||
### Exécution
|
||
|
||
1. Cliquer **Préflight et simuler**.
|
||
2. Vérifier :
|
||
- owner des deux comptes = SPL Token classique ;
|
||
- mint identique sur les deux comptes ;
|
||
- decimals = `9` ;
|
||
- source suffisamment financée ;
|
||
- autorité simple = wallet opérateur ;
|
||
- montant brut conservé exactement.
|
||
3. Cocher la confirmation opérateur.
|
||
4. Cliquer **Signer et envoyer Token**.
|
||
5. Copier la signature dans :
|
||
|
||
```bash
|
||
export KB_DEVNET_SIGNATURE="SIGNATURE_SPL_TOKEN"
|
||
```
|
||
|
||
6. Exécuter `C07`, puis `C12`.
|
||
7. Vérifier les comptes après transfert :
|
||
|
||
```bash
|
||
spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_PROGRAM_ID" display "$KB_DEVNET_CLASSIC_SOURCE_ATA" && spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_PROGRAM_ID" display "$KB_DEVNET_CLASSIC_DESTINATION_ATA"
|
||
```
|
||
|
||
### Critères de validation
|
||
|
||
- simulation réussie ;
|
||
- transaction confirmée puis finalisée ;
|
||
- `operation_code = spl.token.transfer_checked` ;
|
||
- montant brut exact ;
|
||
- insertion canonique, extraction Core et replay réussis ;
|
||
- projection métier présente ;
|
||
- second replay idempotent ;
|
||
- aucun compte Token-2022 impliqué.
|
||
|
||
Le journal métier SPL Token peut rester à `empty` après une simulation seule. Il doit être actualisé après l’envoi confirmé, le replay et la matérialisation.
|
||
|
||
## 10. Scénario S05 — Token-2022
|
||
|
||
### Préparation
|
||
|
||
1. Définir le scénario et exécuter `C06` :
|
||
|
||
```bash
|
||
export KB_DEVNET_SCENARIO="50-spl-token-2022"
|
||
```
|
||
|
||
2. Exécuter `C11` pour créer ou réutiliser la fixture.
|
||
3. Contrôler le mint, la source, la destination et le compte réservé à la fermeture avec les commandes `display` de `C11`.
|
||
4. Dans l’application, ouvrir **Exécution spl_token_2022 — scénarios publics**.
|
||
5. Cliquer **Charger la fixture Token-2022**.
|
||
6. Vérifier que le message indique le chemin de `fixture.env` et le Program ID Token-2022.
|
||
|
||
Le bouton lit le `fixture.env` produit par `kb-pipeline-demo-scenarios` et remplit automatiquement :
|
||
|
||
- compte source ou cible ;
|
||
- mint ;
|
||
- compte destination ou destination lamports ;
|
||
- delegate ;
|
||
- autorité ;
|
||
- freeze authority ;
|
||
- montant brut ;
|
||
- décimales.
|
||
|
||
Ne remplacer manuellement une valeur que pour un test négatif délibéré.
|
||
|
||
### Ordre des sous-scénarios
|
||
|
||
Exécuter les scénarios dans cet ordre, car certains modifient l’état nécessaire aux suivants :
|
||
|
||
#### S05.1 — MintToChecked
|
||
|
||
Champs utilisés :
|
||
|
||
- source/cible : compte token à créditer ;
|
||
- mint : mint Token-2022 ;
|
||
- autorité : mint authority ;
|
||
- montant brut : `TOKEN_2022_MINT_AMOUNT_RAW` chargé depuis la fixture ;
|
||
- décimales : valeur de la fixture.
|
||
|
||
Avec la fixture par défaut, le mint initial est `10000000000` unités brutes, soit 10 tokens avec 9 décimales. Cette quantité couvre ensuite le transfert, l'approbation et le burn prévus.
|
||
|
||
Simuler, envoyer, exécuter `C07`, puis `C12`.
|
||
|
||
#### S05.2 — TransferChecked
|
||
|
||
Champs utilisés :
|
||
|
||
- source : compte financé par S05.1 ;
|
||
- mint ;
|
||
- destination : second compte Token-2022 ;
|
||
- autorité : owner du compte source ;
|
||
- montant brut et décimales.
|
||
|
||
Simuler, envoyer, confirmer et vérifier les balances source/destination.
|
||
|
||
#### S05.3 — ApproveChecked
|
||
|
||
Champs utilisés :
|
||
|
||
- source ;
|
||
- mint ;
|
||
- delegate ;
|
||
- autorité : owner du compte source ;
|
||
- montant brut ;
|
||
- décimales.
|
||
|
||
Après confirmation, vérifier la projection de délégation.
|
||
|
||
#### S05.4 — Revoke
|
||
|
||
Champs utilisés :
|
||
|
||
- source ;
|
||
- autorité : owner du compte source.
|
||
|
||
Le mint et le delegate ne sont pas requis par le formulaire pour cette opération. Vérifier que la délégation précédente est supprimée.
|
||
|
||
#### S05.5 — BurnChecked
|
||
|
||
Champs utilisés :
|
||
|
||
- source ;
|
||
- mint ;
|
||
- autorité : owner du compte source ;
|
||
- montant brut ;
|
||
- décimales.
|
||
|
||
Le compte source doit conserver un solde suffisant après le transfert.
|
||
|
||
#### S05.6 — FreezeAccount
|
||
|
||
Champs utilisés :
|
||
|
||
- source/cible ;
|
||
- mint ;
|
||
- freeze authority.
|
||
|
||
Vérifier que la fixture désigne une freeze authority réellement configurée sur le mint.
|
||
|
||
#### S05.7 — ThawAccount
|
||
|
||
Réutiliser le même compte cible et la même freeze authority. Ce scénario doit suivre FreezeAccount.
|
||
|
||
#### S05.8 — CloseAccount
|
||
|
||
À exécuter uniquement avec le compte de fermeture prévu par la fixture :
|
||
|
||
- source/cible : `closeAccount` chargé par l’application ;
|
||
- destination : autorité/destination lamports chargée ;
|
||
- autorité : owner ou close authority.
|
||
|
||
Le compte doit être vide et satisfaire toutes les préconditions de fermeture.
|
||
|
||
### Pour chaque sous-scénario
|
||
|
||
1. sélectionner le scénario ;
|
||
2. laisser `applyToken2022Fixture` remplir les champs adaptés ;
|
||
3. cliquer **Préflight et simuler** ;
|
||
4. contrôler le plan, les owners, les autorités, le montant et les extensions ;
|
||
5. cocher la confirmation opérateur ;
|
||
6. envoyer ;
|
||
7. définir immédiatement `KB_DEVNET_SIGNATURE` avec la signature affichée pour cette sous-opération ;
|
||
8. vérifier qu'elle diffère de la signature du scénario précédent, puis exécuter `C07` ;
|
||
9. appliquer `C12` ;
|
||
10. conserver un fichier de preuve distinct en modifiant temporairement le préfixe, par exemple :
|
||
|
||
```bash
|
||
export KB_DEVNET_SCENARIO="50a-token-2022-mint-to-checked"
|
||
```
|
||
|
||
puis `50b`, `50c`, etc., avant chaque appel à `C07`.
|
||
|
||
### Critères de validation
|
||
|
||
- chaque opération disponible est simulée sur son message exact ;
|
||
- les comptes sont owned par Token-2022 ;
|
||
- les autorités correspondent à la fixture ;
|
||
- les montants bruts et décimales sont exacts ;
|
||
- les projections token account, admin, fee, metadata ou risk attendues sont présentes selon l’opération ;
|
||
- aucun événement n’est attribué au programme Token classique ;
|
||
- chaque replay est sans échec ;
|
||
- le second replay est idempotent.
|
||
|
||
## 11. Scénario S06 — Registre ElGamal
|
||
|
||
### Objectif
|
||
|
||
Valider le programme indépendant de registre ElGamal sans le confondre avec Token-2022.
|
||
|
||
### Procédure
|
||
|
||
1. Définir puis exécuter `C06` :
|
||
|
||
```bash
|
||
export KB_DEVNET_SCENARIO="60-spl-elgamal-registry"
|
||
```
|
||
|
||
2. Vérifier le Program ID, le PDA de registre, l’owner, la longueur exacte du compte et les preuves requises.
|
||
3. Simuler create/update selon le scénario disponible.
|
||
4. Confirmer l’envoi, exécuter `C07`, puis appliquer `C08`.
|
||
5. Vérifier la projection admin du registre et l’absence de fausse projection Token-2022.
|
||
|
||
## 12. Future fenêtre Metadata
|
||
|
||
La future fenêtre metadata devra suivre la même structure : commandes communes `C01` à `C12`, puis scénarios séparés pour les metadata incorporées Token-2022, Metaplex Token Metadata et l’enrichissement off-chain indépendant.
|
||
|
||
## 13. Critères de clôture de la campagne
|
||
|
||
La campagne est clôturable uniquement lorsque :
|
||
|
||
- tous les scénarios disponibles ont été rejoués depuis une base Devnet propre ;
|
||
- toutes les signatures sont confirmées sur Devnet ;
|
||
- les identités persistées respectent la nomenclature canonique ;
|
||
- aucun ancien `processor_name`, `surface_code`, `operation_code` ou `event_code` ne subsiste ;
|
||
- le replay ciblé est sans échec ni erreur de traitement ;
|
||
- les projections sont présentes et idempotentes ;
|
||
- le présent guide reflète les commandes réellement exécutées.
|