Files
2026-08-18 08:09:20 +02:00

11 KiB

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 :

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é :

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 :

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 :

getTokenAccountBalance
getTokenAccountsByDelegate
getTokenAccountsByOwner
getTokenLargestAccounts
getTokenSupply

Tous passent par la foundation HTTP commune :

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 :

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 :

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 :

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 :

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 :

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 :

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 :

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

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 :

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 :

106 unit tests
11 public API tests
4 release completeness tests

Fichiers ajoutés

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

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

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 :

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 :

getClusterNodes
getEpochInfo
getEpochSchedule
getHighestSnapshotSlot
getIdentity
getMaxRetransmitSlot
getMaxShredInsertSlot