v0.4.8-pre.002

This commit is contained in:
2026-08-05 14:02:33 +02:00
parent 3e7e943d1c
commit 0078956d48
6 changed files with 268 additions and 101 deletions

View File

@@ -0,0 +1,160 @@
<!-- file: docs/audits/V0_4_8_PRE_002_METADATA_CONTRACT_AUDIT.md -->
<!-- version: 1 -->
# Audit contractuel `0.4.8-pre.002` — Solana Program Metadata et Token-2022
## 1. Portée
Cet audit ferme la phase documentaire préalable au code de `0.4.8`. Il compare létat réel du workspace à deux sources officielles distinctes :
- `solana-program/program-metadata` pour le programme `ProgM6JCCvbYkfKqJYHePx4xxSUSqJp7rh8Lyv7nk7S` ;
- `solana-program/token-metadata` et limplémentation Token-2022 pour `spl-token-metadata-interface`.
Aucun code fonctionnel nest ajouté par cette prerelease.
## 2. Sources de vérité retenues
| Surface | Source officielle | Décision |
|---------------------------|-----------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------|
| Solana Program Metadata | dépôt `https://github.com/solana-program/program-metadata`, `README.md`, `idl.json` et sources Rust | lIDL Codama et les sources du programme sont contractuelles ; la copie locale reste brute |
| Token Metadata interface | dépôt `https://github.com/solana-program/token-metadata`, crate `spl-token-metadata-interface` | les cinq discriminateurs et formats Borsh de linterface sont contractuels |
| Implémentation Token-2022 | dépôt `https://github.com/solana-program/token-2022` | Token-2022 est limplémentation ciblée par le workspace ; aucun Program ID metadata autonome nest créé |
Laudit a été réalisé le 5 août 2026. Les implémentations futures doivent continuer à pinner leurs dépendances Cargo et ne pas dépendre implicitement de létat mouvant de la branche `main`.
## 3. Validation de lIDL Solana Program Metadata
Copie locale auditée :
```text
idls/metadata.ProgM6JCCvbYkfKqJYHePx4xxSUSqJp7rh8Lyv7nk7S.solana_program_metadata.V0_0_0.from_github_solana_program.json
```
Résultat :
- standard : Codama `1.0.0` ;
- nom déclaré : `programMetadata` ;
- Program ID déclaré : `ProgM6JCCvbYkfKqJYHePx4xxSUSqJp7rh8Lyv7nk7S` ;
- version déclarée par la source : `0.0.0` ;
- comptes : `Buffer` et `Metadata` ;
- instructions : 9 ;
- PDA : `canonical`, `nonCanonical` et helper conditionnel `metadata` ;
- erreurs : 5 ;
- SHA-256 de la copie locale : `e6874f519d2ecaa8d92e2d58d1caabc130352c98b5a829375efd31636dbbc7a1`.
La structure, le Program ID, la version déclarée, les PDA, les comptes et les neuf instructions concordent avec lIDL officielle consultée. La version `0.0.0` est conservée telle quelle est déclarée ; elle ne doit pas être interprétée comme une version fonctionnelle inventée par Khadhroony.
## 4. Contrat Solana Program Metadata
### 4.1 PDA
| PDA | Seeds |
|---|---|
| canonical | `[program, seed]` |
| non-canonical | `[program, authority, seed]` |
| metadata | helper conditionnel sélectionnant lune des deux dérivations selon la présence dune autorité tierce |
`seed` est une chaîne UTF-8 de taille fixe 16 octets dans lIDL. Le code doit distinguer longueur en octets et nombre de caractères Unicode.
### 4.2 Comptes
`Buffer` contient : discriminateur, programme optionnel zeroable, autorité optionnelle zeroable, indicateur canonical, seed paddé à loffset 14 et données restantes.
`Metadata` contient : discriminateur, programme, autorité optionnelle zeroable, indicateurs mutable et canonical, seed, encodage, compression, format, source de données, longueur de données paddée à loffset 5 et données restantes.
Discriminateurs de compte : `Empty = 0`, `Buffer = 1`, `Metadata = 2`.
### 4.3 Types fermés
- `Encoding` : `None`, `Utf8`, `Base58`, `Base64` ;
- `Compression` : `None`, `Gzip`, `Zlib` ;
- `Format` : `None`, `Json`, `Yaml`, `Toml` ;
- `DataSource` : `Direct`, `Url`, `External` ;
- `ExternalData` : adresse, offset `u32`, longueur optionnelle zeroable `u32`.
Ces valeurs décrivent uniquement les données on-chain. `Url` ne déclenche aucun téléchargement et `External` ne transforme pas automatiquement un autre compte en observation canonique.
### 4.4 Instructions
| Discriminant | Instruction | Comptes | Arguments |
|---:|---|---|---|
| `0` | `write` | `buffer` (writable)<br>`authority` (signer)<br>`sourceBuffer` (optional) | `offset: u32`<br>`data: Option<bytes>` |
| `1` | `initialize` | `metadata` (writable)<br>`authority` (signer)<br>`program`<br>`programData` (optional)<br>`system` (optional) | `seed: Seed`<br>`encoding: Encoding`<br>`compression: Compression`<br>`format: Format`<br>`dataSource: DataSource`<br>`data: Option<bytes>` |
| `2` | `setAuthority` | `account` (writable)<br>`authority` (signer)<br>`program` (optional)<br>`programData` (optional) | `newAuthority: Option<pubkey>` |
| `3` | `setData` | `metadata` (writable)<br>`authority` (signer)<br>`buffer` (writable, optional)<br>`program` (optional)<br>`programData` (optional) | `encoding: Encoding`<br>`compression: Compression`<br>`format: Format`<br>`dataSource: DataSource`<br>`data: Option<bytes>` |
| `4` | `setImmutable` | `metadata` (writable)<br>`authority` (signer)<br>`program` (optional)<br>`programData` (optional) | — |
| `5` | `trim` | `account` (writable)<br>`authority` (signer)<br>`program` (optional)<br>`programData` (optional)<br>`destination` (writable)<br>`rent` | — |
| `6` | `close` | `account` (writable)<br>`authority` (signer)<br>`program` (optional)<br>`programData` (optional)<br>`destination` (writable) | — |
| `7` | `allocate` | `buffer` (writable)<br>`authority` (signer)<br>`program` (optional)<br>`programData` (optional)<br>`system` (optional) | `seed: Option<Seed>` |
| `8` | `extend` | `account` (writable)<br>`authority` (signer)<br>`program` (optional)<br>`programData` (optional) | `length: u16` |
### 4.5 Erreurs officielles
| Code | Erreur |
|---:|---|
| 0 | `NotExecutableAccount` |
| 1 | `InvalidProgramState` |
| 2 | `InvalidProgramDataAccount` |
| 3 | `ImmutableMetadataAccount` |
| 4 | `InvalidDataLength` |
## 5. Décisions de modèles et de validation `ProgM6…`
- le namespace reste `metadata/solana_program_metadata` ;
- `pre.003` doit introduire des modèles publics propres à cette surface ;
- aucune dépendance au modèle Metaplex ou Token-2022 ne doit être créée ;
- le décodeur doit borner explicitement seed, tailles, offsets et longueurs avant allocation ;
- les options zeroable et les options Borsh préfixées sont deux contrats distincts ;
- les builders devront reproduire exactement les discriminateurs `u8` et les encodages little-endian ;
- les comptes optionnels du programme/program-data ne doivent pas être inventés lorsquils sont absents ;
- la fixture Devnet doit utiliser un programme upgradeable contrôlé pour valider le chemin canonical ;
- un autre programme quelconque peut être ciblé pour le chemin non-canonical, puisque lautorité tierce signe ce chemin ;
- les opérations irréversibles, notamment `SetImmutable`, seront soumises uniquement sur des fixtures jetables dédiées.
## 6. Matrice de couverture Token-2022 réelle
| Capacité | Décodage wire | Intent public | Builder | Exécution | Lecture stateful | Matérialisation | Scénario dédié | Desktop | Devnet confirmé |
|---|---|---|---|---|---|---|---|---|---|
| `Initialize` | oui | oui | oui | oui, via builder générique | état extension lisible | extension observée | non dédié | non dédié | non établi |
| `UpdateField` | oui | oui | oui | oui, via builder générique | état extension lisible | extension observée | non dédié | non dédié | non établi |
| `RemoveKey` | oui | oui | oui | oui, via builder générique | état extension lisible | extension observée | non dédié | non dédié | non établi |
| `UpdateAuthority` | oui | non | non | non | état extension lisible | extension observée | non | non | non |
| `Emit` | oui | non | non | non | résultat de retour non orchestré | non dédiée | non | non | non |
Constats complémentaires :
- les cinq discriminateurs sont déjà reconnus dans `kb-lib/src/decoder/spl/token_2022/wire.rs` ;
- le décodeur impose la consommation exacte du payload et rejette les trailing bytes ;
- `UpdateField` prend déjà en charge `Name`, `Symbol`, `Uri` et une clé libre ;
- `RemoveKey` décode déjà le booléen `idempotent` ;
- `UpdateAuthority` décode déjà lautorité nullable ;
- `Emit` décode déjà les bornes optionnelles `start` et `end` ;
- les intents/builders actuels sarrêtent à `Initialize`, `UpdateField` et `RemoveKey` ;
- le stateful Token-2022 sait relire lextension `token_metadata`, mais il nexiste pas encore de parcours dexécution et de postconditions propre aux cinq opérations ;
- aucune preuve Devnet spécifique à cette matrice nest actuellement conservée.
## 7. Découpage fonctionnel confirmé
`pre.003` reste consacré aux modèles Solana Program Metadata. Les phases suivantes conservent la séparation prévue : comptes, instructions, matérialisation, builders/exécuteur, pipeline, campagne Devnet, puis complétude Token-2022.
La complétude Token-2022 devra au minimum ajouter :
- intents et builders `UpdateTokenMetadataAuthority` et `EmitTokenMetadata` ;
- politique de capacité et de signataires ;
- validation des bornes de `Emit` ;
- lecture et vérification post-exécution de lupdate authority ;
- capture exploitable du retour de `Emit` ;
- campagne synthétique et Devnet dédiée ;
- parcours desktop séparé de `ProgM6…`.
## 8. Critère de clôture de `pre.002`
Le contrat est considéré fermé pour commencer le code lorsque :
- les deux surfaces restent distinctes ;
- lIDL officielle locale est validée sans réécriture ;
- les comptes, PDA, types, erreurs et neuf instructions sont inventoriés ;
- la matrice Token-2022 distingue décodage déjà complet et exécution incomplète ;
- les fixtures Devnet nécessaires sont décidées avant leur implémentation.
Ces conditions sont remplies. `0.4.8-pre.003` peut commencer par les modèles Solana Program Metadata.