325 lines
11 KiB
Markdown
325 lines
11 KiB
Markdown
<!-- file: deltas/0.2.2/pre.004.md -->
|
|
<!-- version: 1 -->
|
|
|
|
# Delta `0.2.2-pre.004` — cinq wrappers HTTP Tokens typés
|
|
|
|
## Base requise
|
|
|
|
Livraison précédente corrigée et validée localement par l'opérateur :
|
|
|
|
```text
|
|
0.2.2-pre.003-fix.001
|
|
workspace.package.version = "0.2.2-pre.3.fix.1"
|
|
```
|
|
|
|
La validation opérateur du 2026-08-18 a confirmé :
|
|
|
|
```text
|
|
cargo fmt --all OK
|
|
cargo check --workspace OK
|
|
cargo clippy --workspace --all-targets OK
|
|
cargo test -p ksp-onchain-transport-lib OK
|
|
```
|
|
|
|
Résultats Transport de cette base :
|
|
|
|
```text
|
|
98 unit tests
|
|
10 public API tests
|
|
3 release completeness tests
|
|
0 warning signalé par check/clippy
|
|
```
|
|
|
|
Le plan canonique reste `docs/plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md` version 3.
|
|
|
|
## Objectif
|
|
|
|
Clôturer la famille Tokens attribuée à `0.2.2` avec cinq wrappers publics typés :
|
|
|
|
```text
|
|
getTokenAccountBalance
|
|
getTokenAccountsByDelegate
|
|
getTokenAccountsByOwner
|
|
getTokenLargestAccounts
|
|
getTokenSupply
|
|
```
|
|
|
|
Tous passent par la foundation HTTP commune :
|
|
|
|
```text
|
|
wrapper typé
|
|
-> descriptor audité
|
|
-> execute_standard_rpc
|
|
-> pool/admission/retry/deadline
|
|
-> reqwest HTTP
|
|
-> JSON-RPC validation
|
|
-> décodage DTO KSP
|
|
```
|
|
|
|
Aucun wrapper Token ne contacte `reqwest` directement et aucune crate SPL n'est ajoutée.
|
|
|
|
## Version Cargo
|
|
|
|
Conformément à `VER-ID-009` :
|
|
|
|
```text
|
|
0.2.2-pre.3.fix.1 -> 0.2.2-pre.4
|
|
```
|
|
|
|
Aucune dépendance ni feature Cargo n'est ajoutée ou retirée.
|
|
|
|
## Réaudit ciblé du contrat courant
|
|
|
|
Les pages RPC Solana courantes ont été revérifiées le 2026-08-18 pour cette tranche :
|
|
|
|
```text
|
|
https://solana.com/docs/rpc/http/gettokenaccountbalance
|
|
https://solana.com/docs/rpc/http/gettokenaccountsbydelegate
|
|
https://solana.com/docs/rpc/http/gettokenaccountsbyowner
|
|
https://solana.com/docs/rpc/http/gettokenlargestaccounts
|
|
https://solana.com/docs/rpc/http/gettokensupply
|
|
```
|
|
|
|
Le contrat reste cohérent avec le plan `009` :
|
|
|
|
- `getTokenAccountBalance`, `getTokenLargestAccounts` et `getTokenSupply` acceptent un `commitment` optionnel ;
|
|
- `getTokenAccountsByDelegate` et `getTokenAccountsByOwner` prennent un selector exclusif `{mint}` ou `{programId}` puis une config Account optionnelle ;
|
|
- les cinq réponses sont contextualisées ;
|
|
- les deux méthodes de liste renvoient des `pubkey + account` et réutilisent donc le DTO Account générique ;
|
|
- `TokenAmount.uiAmount` reste nullable ; `uiAmountString` reste la représentation textuelle à préserver ;
|
|
- `getTokenLargestAccounts` renvoie les 20 plus gros token accounts côté RPC, sans que KSP invente un tri supplémentaire.
|
|
|
|
Le réaudit complémentaire Agave `v4.2.1` déjà fixé en `pre.001-fix.001` reste la référence d'implémentation ciblée ; aucune divergence
|
|
nouvelle nécessitant un changement de DTO n'a été identifiée pour cette tranche.
|
|
|
|
## Surface typée Tokens
|
|
|
|
### `getTokenAccountBalance`
|
|
|
|
Signature publique conceptuelle :
|
|
|
|
```text
|
|
role + token account Pubkey + Option<SolanaCommitmentConfig>
|
|
-> SolanaRpcResponse<SolanaTokenAmount>
|
|
```
|
|
|
|
Le wrapper préserve `amount`, `decimals`, `uiAmount` nullable et `uiAmountString`, et conserve une erreur JSON-RPC distante comme erreur
|
|
applicative RPC.
|
|
|
|
### `getTokenAccountsByDelegate`
|
|
|
|
Signature publique conceptuelle :
|
|
|
|
```text
|
|
role + delegate Pubkey + SolanaTokenAccountSelector + Option<SolanaAccountInfoConfig>
|
|
-> SolanaRpcResponse<Vec<SolanaKeyedAccount>>
|
|
```
|
|
|
|
Le selector KSP empêche par construction les objets contenant simultanément `mint` et `programId`. La config Account réutilise les encodings,
|
|
`dataSlice`, `commitment` et `minContextSlot` activés en `pre.003`.
|
|
|
|
### `getTokenAccountsByOwner`
|
|
|
|
Signature publique conceptuelle :
|
|
|
|
```text
|
|
role + owner Pubkey + SolanaTokenAccountSelector + Option<SolanaAccountInfoConfig>
|
|
-> SolanaRpcResponse<Vec<SolanaKeyedAccount>>
|
|
```
|
|
|
|
Le wrapper partage le même chemin privé de sérialisation/décodage que la variante Delegate afin d'éviter deux implémentations de wire parallèles.
|
|
Un config Account explicitement vide est omis du tableau `params`.
|
|
|
|
### `getTokenLargestAccounts`
|
|
|
|
Signature publique conceptuelle :
|
|
|
|
```text
|
|
role + mint Pubkey + Option<SolanaCommitmentConfig>
|
|
-> SolanaRpcResponse<Vec<SolanaTokenAccountBalance>>
|
|
```
|
|
|
|
L'ordre retourné par le serveur est conservé. Chaque `address` est validée et convertie en `ksp_core_lib::Pubkey` sans recopier une valeur wire
|
|
invalide dans le diagnostic.
|
|
|
|
### `getTokenSupply`
|
|
|
|
Signature publique conceptuelle :
|
|
|
|
```text
|
|
role + mint Pubkey + Option<SolanaCommitmentConfig>
|
|
-> SolanaRpcResponse<SolanaTokenAmount>
|
|
```
|
|
|
|
`amount` reste une chaîne exacte et KSP ne convertit pas la supply en type métier SPL ni en entier borné localement.
|
|
|
|
## Mutualisation activée en production
|
|
|
|
Les helpers Token préparés en `pre.002` deviennent production-live uniquement parce qu'ils ont maintenant des consommateurs runtime réels :
|
|
|
|
- sérialisation de `SolanaTokenAccountSelector` ;
|
|
- décodage `SolanaTokenAmount` ;
|
|
- décodage `SolanaTokenAccountBalance` ;
|
|
- wire structs Token privés.
|
|
|
|
`SolanaAccountInfoConfig::is_empty` devient `pub(crate)` pour permettre aux deux wrappers de liste Token de réutiliser la règle d'omission de
|
|
config vide déjà utilisée par Accounts. Cette modification reste interne à la crate et n'élargit pas l'API publique externe.
|
|
|
|
Les helpers Cluster préparatoires restent inchangés et ne deviennent pas production-live avant `pre.005`/`pre.006`.
|
|
|
|
## Validation locale des paramètres
|
|
|
|
Aucun nouveau code d'erreur local n'est nécessaire dans cette tranche :
|
|
|
|
- le selector `Mint | ProgramId` garantit exactement une variante par construction ;
|
|
- les owner/delegate/mint/token-account sont des `Pubkey` typées avant l'appel ;
|
|
- les configs Account/Commitment réutilisent les types déjà validés ;
|
|
- aucune cardinalité supplémentaire documentée ne doit être imposée côté client.
|
|
|
|
`ERROR_CODE_INVALID_RPC_PARAMETERS` introduit en `pre.003` reste inchangé.
|
|
|
|
## Fixtures HTTP déterministes ajoutées
|
|
|
|
```text
|
|
crates/ksp-onchain-transport-lib/fixtures/http/get_token_account_balance.success.json
|
|
crates/ksp-onchain-transport-lib/fixtures/http/get_token_account_balance.error.json
|
|
crates/ksp-onchain-transport-lib/fixtures/http/get_token_accounts_by_delegate.success.json
|
|
crates/ksp-onchain-transport-lib/fixtures/http/get_token_accounts_by_owner.success.json
|
|
crates/ksp-onchain-transport-lib/fixtures/http/get_token_accounts_by_owner.invalid_pubkey.json
|
|
crates/ksp-onchain-transport-lib/fixtures/http/get_token_largest_accounts.success.json
|
|
crates/ksp-onchain-transport-lib/fixtures/http/get_token_largest_accounts.invalid_address.json
|
|
crates/ksp-onchain-transport-lib/fixtures/http/get_token_supply.success.json
|
|
```
|
|
|
|
Les tests utilisent un serveur HTTP loopback et n'accèdent pas à Internet.
|
|
|
|
## Couverture de tests ajoutée
|
|
|
|
Les tests Token couvrent notamment :
|
|
|
|
- request exacte de chacune des cinq méthodes ;
|
|
- selector `programId` pour Delegate ;
|
|
- selector `mint` pour Owner ;
|
|
- config Account complète et omission d'un config explicitement vide ;
|
|
- commitment optionnel ;
|
|
- `uiAmount: null` ;
|
|
- montant/supply textuel exact ;
|
|
- conservation de l'ordre pour `getTokenLargestAccounts` ;
|
|
- décodage `jsonParsed` des accounts sous forme JSON opaque Transport ;
|
|
- erreur JSON-RPC applicative ;
|
|
- rejet d'une `pubkey` ou `address` invalide dans une réponse typée.
|
|
|
|
Le test public compile explicitement les cinq méthodes depuis `HttpTransportPool`.
|
|
|
|
Un canari release fige l'ensemble Tokens `0.2.2` exact :
|
|
|
|
```text
|
|
getTokenAccountBalance
|
|
getTokenAccountsByDelegate
|
|
getTokenAccountsByOwner
|
|
getTokenLargestAccounts
|
|
getTokenSupply
|
|
```
|
|
|
|
Il vérifie également `Read + RetrySafe` pour chacun. Les 12 wrappers Cluster restent hors de cette tranche.
|
|
|
|
Après application, la cible Transport attendue devient :
|
|
|
|
```text
|
|
106 unit tests
|
|
11 public API tests
|
|
4 release completeness tests
|
|
```
|
|
|
|
## Fichiers ajoutés
|
|
|
|
```text
|
|
crates/ksp-onchain-transport-lib/fixtures/http/get_token_account_balance.success.json
|
|
crates/ksp-onchain-transport-lib/fixtures/http/get_token_account_balance.error.json
|
|
crates/ksp-onchain-transport-lib/fixtures/http/get_token_accounts_by_delegate.success.json
|
|
crates/ksp-onchain-transport-lib/fixtures/http/get_token_accounts_by_owner.success.json
|
|
crates/ksp-onchain-transport-lib/fixtures/http/get_token_accounts_by_owner.invalid_pubkey.json
|
|
crates/ksp-onchain-transport-lib/fixtures/http/get_token_largest_accounts.success.json
|
|
crates/ksp-onchain-transport-lib/fixtures/http/get_token_largest_accounts.invalid_address.json
|
|
crates/ksp-onchain-transport-lib/fixtures/http/get_token_supply.success.json
|
|
deltas/0.2.2/pre.004.md
|
|
```
|
|
|
|
## Fichiers modifiés
|
|
|
|
```text
|
|
Cargo.toml
|
|
crates/ksp-onchain-transport-lib/src/lib.rs
|
|
crates/ksp-onchain-transport-lib/src/rpc_accounts.rs
|
|
crates/ksp-onchain-transport-lib/src/rpc_tokens.rs
|
|
crates/ksp-onchain-transport-lib/unit_tests/rpc_tokens.rs
|
|
crates/ksp-onchain-transport-lib/tests/public_api.rs
|
|
crates/ksp-onchain-transport-lib/tests/release_completeness.rs
|
|
```
|
|
|
|
## Fichiers supprimés
|
|
|
|
Aucun.
|
|
|
|
## Fichiers volontairement inchangés
|
|
|
|
```text
|
|
deltas/0.2.2/pre.003.md
|
|
deltas/0.2.2/pre.003-fix.001.md
|
|
docs/plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md
|
|
ROADMAP.md
|
|
CHANGELOG.md
|
|
crates/ksp-onchain-transport-lib/src/rpc_common.rs
|
|
crates/ksp-onchain-transport-lib/src/rpc_cluster.rs
|
|
crates/ksp-onchain-transport-lib/src/rpc_method.rs
|
|
crates/ksp-config-lib/**
|
|
config/**
|
|
```
|
|
|
|
Les deltas déjà publiés restent des traces historiques et ne sont pas réécrits.
|
|
|
|
## Contrôles statiques effectués pendant la préparation
|
|
|
|
- `workspace.package.version` vaut `0.2.2-pre.4` ;
|
|
- les huit nouvelles fixtures JSON sont syntaxiquement valides ;
|
|
- les cinq wrappers utilisent `execute_standard_rpc` ;
|
|
- aucun `reqwest` direct n'est ajouté dans `rpc_tokens.rs` ;
|
|
- aucun `#[allow(dead_code)]` ou suppression de lint n'est ajouté ;
|
|
- aucun helper Cluster n'est activé en production ;
|
|
- aucune dépendance ou feature Cargo n'est ajoutée ;
|
|
- aucune crate SPL n'est importée ;
|
|
- la surface publique Accounts de `pre.003` reste présente ;
|
|
- les deltas historiques restent inchangés.
|
|
|
|
## Validations Rust non exécutées dans le sandbox
|
|
|
|
Le sandbox de préparation ne fournit pas la toolchain Cargo utilisée par le checkout opérateur. Les commandes suivantes doivent donc être rejouées
|
|
après application :
|
|
|
|
```bash
|
|
cargo fmt --all
|
|
cargo check --workspace
|
|
cargo clippy --workspace --all-targets
|
|
cargo test -p ksp-onchain-transport-lib
|
|
```
|
|
|
|
Les validations ne sont pas déclarées réussies tant qu'elles n'ont pas été exécutées sur le checkout opérateur.
|
|
|
|
## Questions ouvertes
|
|
|
|
Aucune question bloquante.
|
|
|
|
## Suite
|
|
|
|
Après validation et commit de `0.2.2-pre.004`, poursuivre avec `0.2.2-pre.005` pour les sept wrappers Cluster simples :
|
|
|
|
```text
|
|
getClusterNodes
|
|
getEpochInfo
|
|
getEpochSchedule
|
|
getHighestSnapshotSlot
|
|
getIdentity
|
|
getMaxRetransmitSlot
|
|
getMaxShredInsertSlot
|
|
```
|