From f0493df09e1950a053496ee1f31fc4b9a24186c2 Mon Sep 17 00:00:00 2001 From: SinuS Von SifriduS Date: Thu, 27 Aug 2026 15:18:34 +0200 Subject: [PATCH] v0.2.12-pre.008-fix.002 --- Cargo.toml | 4 +- crates/ksp-app-wallet-desk/frontend/main.html | 7 +- .../ksp-app-wallet-desk/frontend/ts/main.ts | 15 +++- crates/ksp-app-wallet-desk/package.json | 2 +- crates/ksp-app-wallet-desk/src/app_state.rs | 6 +- crates/ksp-app-wallet-desk/src/lib.rs | 4 +- .../ksp-app-wallet-desk/src/wallet_balance.rs | 56 ++++++++++++- crates/ksp-app-wallet-desk/tauri.conf.json | 2 +- .../tests/desktop_contract.rs | 22 +++--- .../unit_tests/wallet_balance.rs | 12 ++- deltas/0.2.12/pre.008-fix.002.md | 78 +++++++++++++++++++ .../plans/019-V0_2_12_SOL_PRICES_DESK_PLAN.md | 14 +++- .../validation/015-V0_2_12_SOL_PRICES_DESK.md | 64 ++++++++++++--- 13 files changed, 248 insertions(+), 38 deletions(-) create mode 100644 deltas/0.2.12/pre.008-fix.002.md diff --git a/Cargo.toml b/Cargo.toml index 686f517..8d1f7d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ # file: Cargo.toml -# version: 296 +# version: 297 [workspace] resolver = "3" members = ["crates/ksp-app-config-desk", "crates/ksp-app-solprices-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-wallet-lib"] [workspace.package] -version = "0.2.12-pre.8.fix.1" +version = "0.2.12-pre.8.fix.2" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" diff --git a/crates/ksp-app-wallet-desk/frontend/main.html b/crates/ksp-app-wallet-desk/frontend/main.html index df91c34..5bd5934 100644 --- a/crates/ksp-app-wallet-desk/frontend/main.html +++ b/crates/ksp-app-wallet-desk/frontend/main.html @@ -1,5 +1,5 @@ - + @@ -53,7 +53,7 @@

Dashboard

Identité autorisée et balance SOL via le Transport HTTP composite sont actives.

- 0.2.6 +
@@ -98,6 +98,7 @@
Notes
Balance SOL
SOL/USD moyen
N.A.
+
Équivalent USD
N.A.
@@ -257,6 +258,8 @@
Notes
Lamports
SOL
+
SOL/USD moyen
N.A.
+
Équivalent USD
N.A.
RPC slot
RPC api_version
Transport
diff --git a/crates/ksp-app-wallet-desk/frontend/ts/main.ts b/crates/ksp-app-wallet-desk/frontend/ts/main.ts index f8d3e77..acb3359 100644 --- a/crates/ksp-app-wallet-desk/frontend/ts/main.ts +++ b/crates/ksp-app-wallet-desk/frontend/ts/main.ts @@ -1,5 +1,5 @@ // file: crates/ksp-app-wallet-desk/frontend/ts/main.ts -// version: 17 +// version: 18 import { Modal } from "bootstrap"; import DataTable from "datatables.net-bs5"; @@ -379,8 +379,11 @@ function clearStrongViewSensitiveInputs(): void { function clearBalanceProjection(): void { setText("#currentWalletBalanceSol", "—"); setText("#currentWalletSolUsdAverage", "N.A."); + setText("#currentWalletSolUsdEquivalent", "N.A."); setText("#detailsBalanceLamports", "—"); setText("#detailsBalanceSol", "—"); + setText("#detailsSolUsdAverage", "N.A."); + setText("#detailsSolUsdEquivalent", "N.A."); setText("#detailsBalanceSlot", "—"); setText("#detailsBalanceApiVersion", "—"); setText("#detailsBalanceTransport", "—"); @@ -1380,14 +1383,17 @@ function renderWalletBalance(balance: WalletBalanceDto): void { return; } setText("#currentWalletBalanceSol", balance.sol); - setText("#currentWalletSolUsdAverage", balance.solUsdAverage ? `${balance.solUsdAverage} USD` : "N.A."); + setText("#currentWalletSolUsdAverage", balance.solUsdAverage ? `${balance.solUsdAverage} USD/SOL` : "N.A."); + setText("#currentWalletSolUsdEquivalent", balance.solUsdEquivalent ? `${balance.solUsdEquivalent} USD` : "N.A."); setText("#detailsBalanceLamports", balance.lamports); setText("#detailsBalanceSol", balance.sol); + setText("#detailsSolUsdAverage", balance.solUsdAverage ? `${balance.solUsdAverage} USD/SOL` : "N.A."); + setText("#detailsSolUsdEquivalent", balance.solUsdEquivalent ? `${balance.solUsdEquivalent} USD` : "N.A."); setText("#detailsBalanceSlot", balance.slot.toString()); setText("#detailsBalanceApiVersion", balance.apiVersion ?? "—"); setText("#detailsBalanceTransport", `${balance.transportProfile} / ${balance.transportRole}`); - setText("#balanceStatus", "Balance réseau et prix moyen SOL/USD actualisés."); - frontendInfo("main", "Wallet balance rendered", { averageAvailable: balance.solUsdAverage !== null, lamports: balance.lamports, slot: balance.slot, walletId: balance.walletId }); + setText("#balanceStatus", "Balance réseau, prix moyen SOL/USD et équivalent USD actualisés."); + frontendInfo("main", "Wallet balance rendered", { averageAvailable: balance.solUsdAverage !== null, equivalentAvailable: balance.solUsdEquivalent !== null, lamports: balance.lamports, slot: balance.slot, walletId: balance.walletId }); } async function refreshWalletBalance(): Promise { @@ -1417,6 +1423,7 @@ function bindBalanceActions(): void { } function renderRuntimeStatus(status: RuntimeStatusDto): void { + setText("#appVersionBadge", status.applicationVersion); setText("#runtimeVersion", status.applicationVersion); setText("#runtimeCompositeProfile", status.activeCompositeProfile); setText("#runtimeLoggingProfile", status.activeLoggingProfile ?? "fallback transitoire"); diff --git a/crates/ksp-app-wallet-desk/package.json b/crates/ksp-app-wallet-desk/package.json index 30532d5..3688b2c 100644 --- a/crates/ksp-app-wallet-desk/package.json +++ b/crates/ksp-app-wallet-desk/package.json @@ -1,7 +1,7 @@ { "name": "ksp-app-wallet-desk", "private": true, - "version": "0.2.12-pre.8.fix.1", + "version": "0.2.12-pre.8.fix.2", "type": "module", "scripts": { "dev": "vite", diff --git a/crates/ksp-app-wallet-desk/src/app_state.rs b/crates/ksp-app-wallet-desk/src/app_state.rs index c8face0..a133177 100644 --- a/crates/ksp-app-wallet-desk/src/app_state.rs +++ b/crates/ksp-app-wallet-desk/src/app_state.rs @@ -1,5 +1,5 @@ // file: crates/ksp-app-wallet-desk/src/app_state.rs -// version: 20 +// version: 21 //! Shared backend state owned by the Wallet Desk Tauri application. @@ -1160,17 +1160,19 @@ impl AppState { )); } let lamports = result.value(); + let sol_usd_equivalent = crate::sol_usd_equivalent(lamports, sol_usd_average.as_deref()); let dto = crate::WalletBalanceDto { api_version: result.context().api_version().map(str::to_owned), lamports: lamports.to_string(), slot: result.context().slot(), sol: crate::format_lamports_as_sol(lamports), sol_usd_average, + sol_usd_equivalent, transport_profile: self.transport_runtime.profile_id().to_owned(), transport_role: self.transport_runtime.role().as_str().to_owned(), wallet_id: context.wallet_id.clone(), }; - ksp_logging_lib::info!(target: crate::TRACING_TARGET, domain = crate::TRACING_DOMAIN_TRANSPORT, wallet_id = context.wallet_id.as_str(), capability = context.capability, lamports, slot = dto.slot, sol_usd_average_available = dto.sol_usd_average.is_some(), "Wallet balance refresh succeeded"); + ksp_logging_lib::info!(target: crate::TRACING_TARGET, domain = crate::TRACING_DOMAIN_TRANSPORT, wallet_id = context.wallet_id.as_str(), capability = context.capability, lamports, slot = dto.slot, sol_usd_average_available = dto.sol_usd_average.is_some(), sol_usd_equivalent_available = dto.sol_usd_equivalent.is_some(), "Wallet balance refresh succeeded"); return std::result::Result::Ok(dto); } diff --git a/crates/ksp-app-wallet-desk/src/lib.rs b/crates/ksp-app-wallet-desk/src/lib.rs index 13425a3..cc56958 100644 --- a/crates/ksp-app-wallet-desk/src/lib.rs +++ b/crates/ksp-app-wallet-desk/src/lib.rs @@ -1,5 +1,5 @@ // file: crates/ksp-app-wallet-desk/src/lib.rs -// version: 14 +// version: 15 //! Tauri desktop application shell for KSP Wallet management and inspection. @@ -168,6 +168,8 @@ pub(crate) use self::wallet_balance::WalletBalanceDto; pub(crate) use self::wallet_balance::average_sol_usd_prices; /// Formats exact lamports as a decimal SOL string without floating point. pub(crate) use self::wallet_balance::format_lamports_as_sol; +/// Computes the exact USD equivalent of a lamport balance from the auxiliary SOL/USD average. +pub(crate) use self::wallet_balance::sol_usd_equivalent; /// Resolved Wallet Config and directory preparation status captured during application bootstrap. pub(crate) use self::wallet_config::WalletConfigStartup; /// Resolves the composite-selected Wallet Config and prepares its application-owned directory tree. diff --git a/crates/ksp-app-wallet-desk/src/wallet_balance.rs b/crates/ksp-app-wallet-desk/src/wallet_balance.rs index cfa5850..ec23ec8 100644 --- a/crates/ksp-app-wallet-desk/src/wallet_balance.rs +++ b/crates/ksp-app-wallet-desk/src/wallet_balance.rs @@ -1,5 +1,5 @@ // file: crates/ksp-app-wallet-desk/src/wallet_balance.rs -// version: 3 +// version: 4 //! Safe Wallet balance projection produced by the typed HTTP Transport path. @@ -20,6 +20,8 @@ pub(crate) struct WalletBalanceDto { pub(crate) sol: String, /// Arithmetic mean of successful SOL/USD observations produced by this refresh, or unavailable when no provider returned one. pub(crate) sol_usd_average: std::option::Option, + /// Exact USD equivalent of the current SOL balance using `sol_usd_average`, or unavailable when the auxiliary price is unavailable. + pub(crate) sol_usd_equivalent: std::option::Option, /// Composite-selected Transport profile used for the RPC. pub(crate) transport_profile: String, /// Logical Transport role used for the RPC. @@ -111,6 +113,58 @@ pub(crate) fn average_sol_usd_prices(prices: &[ksp_offchain_transport_lib::Marke return std::option::Option::Some(format_scaled_decimal(coefficient, target_scale)); } +/// Computes the exact USD equivalent of a lamport balance from the current SOL/USD average. +/// +/// The output is rounded half-up to at most eight fractional digits. Missing or invalid auxiliary price data and arithmetic overflow degrade to `None`; the +/// authoritative SOL balance remains unaffected. +#[must_use] +pub(crate) fn sol_usd_equivalent(lamports: u64, sol_usd_average: std::option::Option<&str>) -> std::option::Option { + const LAMPORT_SCALE: u8 = 9; + const OUTPUT_SCALE: u8 = 8; + let source = match sol_usd_average { + std::option::Option::Some(value) => value, + std::option::Option::None => return std::option::Option::None, + }; + let average = match ksp_offchain_transport_lib::MarketPriceDecimal::parse(source) { + std::result::Result::Ok(value) => value, + std::result::Result::Err(_) => return std::option::Option::None, + }; + let coefficient = match u128::from(lamports).checked_mul(average.coefficient()) { + std::option::Option::Some(value) => value, + std::option::Option::None => return std::option::Option::None, + }; + let source_scale = u16::from(LAMPORT_SCALE) + u16::from(average.scale()); + let target_scale = u16::from(OUTPUT_SCALE); + let rounded_coefficient = if source_scale <= target_scale { + let exponent = u32::from(target_scale - source_scale); + let factor = match 10_u128.checked_pow(exponent) { + std::option::Option::Some(value) => value, + std::option::Option::None => return std::option::Option::None, + }; + match coefficient.checked_mul(factor) { + std::option::Option::Some(value) => value, + std::option::Option::None => return std::option::Option::None, + } + } else { + let exponent = u32::from(source_scale - target_scale); + let divisor = match 10_u128.checked_pow(exponent) { + std::option::Option::Some(value) => value, + std::option::Option::None => return std::option::Option::None, + }; + let quotient = coefficient / divisor; + let remainder = coefficient % divisor; + if remainder >= divisor.div_ceil(2) { + match quotient.checked_add(1) { + std::option::Option::Some(value) => value, + std::option::Option::None => return std::option::Option::None, + } + } else { + quotient + } + }; + return std::option::Option::Some(format_scaled_decimal(rounded_coefficient, OUTPUT_SCALE)); +} + fn format_scaled_decimal(mut coefficient: u128, mut scale: u8) -> String { while scale > 0 && coefficient.is_multiple_of(10) { coefficient /= 10; diff --git a/crates/ksp-app-wallet-desk/tauri.conf.json b/crates/ksp-app-wallet-desk/tauri.conf.json index 77d67c2..54e3e13 100644 --- a/crates/ksp-app-wallet-desk/tauri.conf.json +++ b/crates/ksp-app-wallet-desk/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "KSP Wallet Desk", - "version": "0.2.12-pre.8.fix.1", + "version": "0.2.12-pre.8.fix.2", "identifier": "com.sasedev.ksp-app-wallet-desk", "build": { "beforeDevCommand": { diff --git a/crates/ksp-app-wallet-desk/tests/desktop_contract.rs b/crates/ksp-app-wallet-desk/tests/desktop_contract.rs index b36a70e..86ec4a3 100644 --- a/crates/ksp-app-wallet-desk/tests/desktop_contract.rs +++ b/crates/ksp-app-wallet-desk/tests/desktop_contract.rs @@ -1,5 +1,5 @@ // file: crates/ksp-app-wallet-desk/tests/desktop_contract.rs -// version: 26 +// version: 27 //! Desktop build, shell and Config-status contract audits for Wallet Desk. @@ -465,10 +465,6 @@ fn pre_018_packaged_runtime_bundles_config_resources_and_keeps_wallet_desk_versi let package_version = package.pointer("/version").and_then(serde_json::Value::as_str); assert_packaged_version_floor(package_version, "package.json"); assert_eq!(tauri_version, package_version, "desktop package metadata versions must remain synchronized"); - let packaged_version = match package_version { - std::option::Option::Some(value) => value, - std::option::Option::None => return, - }; let resources = tauri.pointer("/bundle/resources").and_then(serde_json::Value::as_object); assert!(resources.is_some(), "packaged Wallet Desk Config resources map must exist"); if let std::option::Option::Some(resources) = resources { @@ -495,7 +491,9 @@ fn pre_018_packaged_runtime_bundles_config_resources_and_keeps_wallet_desk_versi ); } let main = read_text(root.join("frontend/main.html").as_path()); - assert!(main.contains(packaged_version)); + let main_ts = read_text(root.join("frontend/ts/main.ts").as_path()); + assert!(main.contains(r#"id="appVersionBadge""#)); + assert!(main_ts.contains(r#"setText("#appVersionBadge", status.applicationVersion);"#)); let tauri_source = read_text(root.join("src/tauri.rs").as_path()); assert!(tauri_source.contains("ksp_config_lib::prepare_packaged_runtime")); assert!(tauri_source.contains("tauri::utils::platform::resource_dir")); @@ -503,7 +501,7 @@ fn pre_018_packaged_runtime_bundles_config_resources_and_keeps_wallet_desk_versi } #[test] -fn v0_2_12_pre_008_wallet_balance_refresh_adds_one_auxiliary_sol_usd_average_only() { +fn v0_2_12_pre_008_wallet_balance_refresh_adds_average_and_exact_usd_equivalent() { let root = app_root(); let manifest = read_text(root.join("Cargo.toml").as_path()); let composite = read_text(root.join("../../config/composite.ksp-app-wallet-desk.json").as_path()); @@ -519,10 +517,16 @@ fn v0_2_12_pre_008_wallet_balance_refresh_adds_one_auxiliary_sol_usd_average_onl assert!(state.contains("tokio::join!")); assert!(state.contains("refresh_all().await")); assert!(balance.contains("sol_usd_average")); + assert!(balance.contains("sol_usd_equivalent")); assert!(balance.contains("average_sol_usd_prices")); assert!(html.contains(r#"id="currentWalletSolUsdAverage""#)); - assert_eq!(html.matches("currentWalletSolUsdAverage").count(), 1); - assert!(main.contains(r#"balance.solUsdAverage ? `${balance.solUsdAverage} USD` : "N.A.""#)); + assert!(html.contains(r#"id="currentWalletSolUsdEquivalent""#)); + assert!(html.contains(r#"id="detailsSolUsdAverage""#)); + assert!(html.contains(r#"id="detailsSolUsdEquivalent""#)); + assert!(main.contains(r#"balance.solUsdAverage ? `${balance.solUsdAverage} USD/SOL` : "N.A.""#)); + assert!(main.contains(r#"balance.solUsdEquivalent ? `${balance.solUsdEquivalent} USD` : "N.A.""#)); + assert!(!main.contains("parseFloat(")); + assert!(!main.contains("Number(balance.sol")); assert!(!main.contains("refresh_market_price")); assert!(!main.contains("refresh_all_market_prices")); assert!(!main.contains("fetch(")); diff --git a/crates/ksp-app-wallet-desk/unit_tests/wallet_balance.rs b/crates/ksp-app-wallet-desk/unit_tests/wallet_balance.rs index e9cc9b9..b5bb293 100644 --- a/crates/ksp-app-wallet-desk/unit_tests/wallet_balance.rs +++ b/crates/ksp-app-wallet-desk/unit_tests/wallet_balance.rs @@ -1,5 +1,5 @@ // file: crates/ksp-app-wallet-desk/unit_tests/wallet_balance.rs -// version: 2 +// version: 3 //! Unit tests for exact Wallet balance presentation. @@ -31,3 +31,13 @@ fn sol_usd_average_returns_none_without_observation_and_handles_integer_fraction assert_eq!(crate::average_sol_usd_prices(&[one, two]), std::option::Option::Some("1.5".to_owned())); } } + +#[test] +fn sol_usd_equivalent_is_exact_rounded_and_unavailable_without_average() { + assert_eq!(crate::sol_usd_equivalent(0, std::option::Option::Some("104.01730745")), std::option::Option::Some("0".to_owned())); + assert_eq!(crate::sol_usd_equivalent(1_000_000_000, std::option::Option::Some("104.01730745")), std::option::Option::Some("104.01730745".to_owned()),); + assert_eq!(crate::sol_usd_equivalent(1_500_000_000, std::option::Option::Some("104.01730745")), std::option::Option::Some("156.02596118".to_owned()),); + assert_eq!(crate::sol_usd_equivalent(1, std::option::Option::Some("104.01730745")), std::option::Option::Some("0.0000001".to_owned())); + assert_eq!(crate::sol_usd_equivalent(1_000_000_000, std::option::Option::None), std::option::Option::None); + assert_eq!(crate::sol_usd_equivalent(1_000_000_000, std::option::Option::Some("invalid")), std::option::Option::None); +} diff --git a/deltas/0.2.12/pre.008-fix.002.md b/deltas/0.2.12/pre.008-fix.002.md new file mode 100644 index 0000000..0d0696d --- /dev/null +++ b/deltas/0.2.12/pre.008-fix.002.md @@ -0,0 +1,78 @@ + + + +# Delta `0.2.12-pre.008-fix.002` — équivalent USD Wallet et version desktop dynamique + +## Base + +```text +0.2.12-pre.008-fix.001 +``` + +## Cause + +Le gate opérateur de `pre.008-fix.001` confirme `cargo fmt`, les audits KSP, `cargo check --workspace`, Clippy et le démarrage Tauri. Le refresh Wallet exécute aussi correctement `getBalance` et la collecte SOL/USD : huit providers sont chargés, six observations sont produites et la moyenne est disponible. + +Deux écarts restent néanmoins visibles : + +- la vue Details n'affiche ni le prix moyen SOL/USD calculé ni l'équivalent USD de la balance demandé par l'opérateur ; +- le badge principal de Wallet Desk reste figé à `0.2.6`, et le canari historique de packaging recherche encore une version littérale dans `frontend/main.html`, ce qui fait échouer `cargo test -p ksp-app-wallet-desk` après le passage à `0.2.12-pre.8.fix.1`. + +## Correctif + +- version workspace : `0.2.12-pre.8.fix.2` ; +- versions npm/Tauri Wallet Desk synchronisées sur `0.2.12-pre.8.fix.2` ; +- `WalletBalanceDto` gagne `sol_usd_equivalent: Option` ; +- l'équivalent USD est calculé côté Rust à partir des lamports et de `sol_usd_average`, sans `f64`/`f32`, avec arrondi half-up à huit décimales maximum et dégradation à `None` si le prix auxiliaire est absent ou si l'arithmétique ne peut pas être représentée ; +- Dashboard et Details affichent désormais le prix moyen en `USD/SOL` et l'équivalent de la balance en `USD`, ou `N.A.` lorsque la moyenne auxiliaire est indisponible ; +- le badge statique `0.2.6` est remplacé par un élément alimenté par `RuntimeStatusDto.application_version` ; +- le canari `pre_018_packaged_runtime_bundles_config_resources_and_keeps_wallet_desk_version_coherent` vérifie le binding dynamique de version au lieu de rechercher la version courante en littéral dans le HTML ; +- les canaris `pre.008` vérifient l'absence de calcul flottant frontend et la présence des projections moyenne/équivalent dans Dashboard et Details. + +## Invariants préservés + +```text +getBalance autoritatif inchangé +MarketPriceService::refresh_all inchangé +providers utilisés pour la moyenne succès du refresh courant uniquement +prix auxiliaire indisponible balance SOL valide, moyenne/équivalent N.A. +provider_id / URL / credential frontend absents +commande prix dédiée Wallet absente +fetch / calcul prix frontend absents +WalletSession VIEW/OWNER inchangée +``` + +Aucune donnée provider détaillée n'est ajoutée à Wallet Desk. L'équivalent USD est une projection auxiliaire dérivée de la moyenne déjà calculée par `pre.008` ; SOL Prices Desk reste l'application dédiée aux observations et disponibilités provider par provider. + +## Fichiers modifiés/ajoutés + +```text +Cargo.toml +crates/ksp-app-wallet-desk/package.json +crates/ksp-app-wallet-desk/tauri.conf.json +crates/ksp-app-wallet-desk/frontend/main.html +crates/ksp-app-wallet-desk/frontend/ts/main.ts +crates/ksp-app-wallet-desk/src/app_state.rs +crates/ksp-app-wallet-desk/src/lib.rs +crates/ksp-app-wallet-desk/src/wallet_balance.rs +crates/ksp-app-wallet-desk/tests/desktop_contract.rs +crates/ksp-app-wallet-desk/unit_tests/wallet_balance.rs +docs/plans/019-V0_2_12_SOL_PRICES_DESK_PLAN.md +docs/validation/015-V0_2_12_SOL_PRICES_DESK.md +deltas/0.2.12/pre.008-fix.002.md +``` + +## Gate opérateur attendu + +```bash +cargo fmt --all +python3 scripts/audit_rust_workspace_rules.py +python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.2.12 +cargo check --workspace +cargo clippy --workspace --all-targets +cargo test -p ksp-app-wallet-desk +cargo test --workspace +(cd crates/ksp-app-wallet-desk && cargo tauri dev) +``` + +Le contrôle manuel doit confirmer que Details affiche le prix moyen SOL/USD et l'équivalent USD après `Refresh balance`, que Dashboard reflète les mêmes valeurs, et que le badge d'application n'affiche plus une version statique obsolète. diff --git a/docs/plans/019-V0_2_12_SOL_PRICES_DESK_PLAN.md b/docs/plans/019-V0_2_12_SOL_PRICES_DESK_PLAN.md index b4d7626..0cf5cbc 100644 --- a/docs/plans/019-V0_2_12_SOL_PRICES_DESK_PLAN.md +++ b/docs/plans/019-V0_2_12_SOL_PRICES_DESK_PLAN.md @@ -1,5 +1,5 @@ - + # Plan `0.2.12` — SOL Prices Desk + intégration prix Wallet Desk @@ -555,15 +555,21 @@ Finalisation de la table responsive sans changer le contrat de dispatch : résum ### `pre.008` — Intégration Wallet minimale + recalibrage de clôture -**Statut : implémenté ; corrigé par `pre.008-fix.001`, gate opérateur à confirmer.** +**Statut : réalisé ; corrigé par `pre.008-fix.001` puis `pre.008-fix.002`, gate opérateur final à confirmer.** -Absorption de l'ancien couloir Wallet `pre.009`–`pre.011` dans une seule tranche : ajout `offchain_transport/public_keyless` au composite Wallet, runtime Off-chain auxiliaire, `refresh_all` lors de `refresh_wallet_balance`, moyenne SOL/USD backend sans `f64`, `WalletBalanceDto.sol_usd_average` et une seule case UI `SOL/USD moyen`/`N.A.`. Aucun panneau provider, aucune command prix Wallet, aucun provider ID frontend et aucune valorisation USD du solde. La tranche réconcilie également le présent forecast avec cette réduction de scope. +Absorption de l'ancien couloir Wallet `pre.009`–`pre.011` dans une seule tranche : ajout `offchain_transport/public_keyless` au composite Wallet, runtime Off-chain auxiliaire, `refresh_all` lors de `refresh_wallet_balance`, moyenne SOL/USD backend sans `f64` et projection compacte dans Wallet Desk. La correction `fix.002` complète le besoin opérateur réellement attendu : `WalletBalanceDto` expose également un équivalent USD exact calculé côté Rust à partir des lamports et de la moyenne du refresh courant ; Dashboard et Details affichent le prix moyen et l'équivalent ou `N.A.`. Aucun panneau provider, aucune command prix Wallet et aucun provider ID frontend ne sont ajoutés. La tranche réconcilie également le forecast avec cette réduction de scope. #### `pre.008-fix.001` — Correction du canari desktop et Clippy de la moyenne +**Statut : réalisé ; gate opérateur technique partiellement PASS, interrompu par un canari historique de version.** + +Le premier gate de `pre.008` confirme `cargo check --workspace` mais révèle deux défauts purement techniques : des littéraux Rust non échappés dans le nouveau canari `desktop_contract.rs`, qui empêchent `cargo fmt` et les targets de test de parser le fichier, et un warning Clippy `manual_is_multiple_of` dans le formateur décimal Wallet. Le fix remplace les littéraux fragiles par des raw strings Rust et applique `u128::is_multiple_of(10)`. Son gate confirme ensuite `fmt`, audits, `check` et Clippy, puis s'arrête sur le canari `pre_018_packaged_runtime_bundles_config_resources_and_keeps_wallet_desk_version_coherent`, encore couplé à une version littérale dans le HTML. Le runtime Tauri et le refresh balance/prix fonctionnent. + +#### `pre.008-fix.002` — Équivalent USD, projection Details et version desktop dynamique + **Statut : implémenté ; gate opérateur à confirmer.** -Le premier gate de `pre.008` confirme `cargo check --workspace` mais révèle deux défauts purement techniques : des littéraux Rust non échappés dans le nouveau canari `desktop_contract.rs`, qui empêchent `cargo fmt` et les targets de test de parser le fichier, et un warning Clippy `manual_is_multiple_of` dans le formateur décimal Wallet. Le fix remplace les littéraux fragiles par des raw strings Rust et applique `u128::is_multiple_of(10)`. Aucune logique de moyenne, aucun appel Off-chain, aucun DTO ni aucune UI n'est modifié. +Correction du dernier écart fonctionnel de la tranche : le refresh produisait bien une moyenne SOL/USD mais elle n'était visible que dans le résumé Dashboard, tandis que Details n'affichait ni cette moyenne ni la valeur USD équivalente de la balance. `WalletBalanceDto.sol_usd_equivalent` est désormais calculé côté Rust sans flottant, à partir des lamports et de `sol_usd_average`, avec arrondi half-up à huit décimales maximum ; l'UI rend moyenne et équivalent dans Dashboard et Details, ou `N.A.` si le prix auxiliaire est indisponible. Le badge statique `0.2.6` est remplacé par `RuntimeStatusDto.application_version`, et le canari packaging vérifie ce binding version-neutral au lieu d'exiger la version courante en littéral dans `main.html`. ### `pre.009` — Hardening transversal + gate technique/live final diff --git a/docs/validation/015-V0_2_12_SOL_PRICES_DESK.md b/docs/validation/015-V0_2_12_SOL_PRICES_DESK.md index bc1635a..f3e3975 100644 --- a/docs/validation/015-V0_2_12_SOL_PRICES_DESK.md +++ b/docs/validation/015-V0_2_12_SOL_PRICES_DESK.md @@ -1,5 +1,5 @@ - + # Validation `0.2.12` — SOL Prices Desk + intégration Wallet Desk @@ -586,9 +586,10 @@ getBalance + refresh_all lancés dans l observations prises pour moyenne uniquement succès du refresh courant moyenne backend, aucune conversion f64, 8 décimales max WalletBalanceDto.sol_usd_average Option -UI Wallet une case SOL/USD moyen / N.A. +WalletBalanceDto.sol_usd_equivalent Option, calcul exact backend +UI Wallet moyenne + équivalent dans Dashboard/Details, sinon N.A. provider_id / URL / credential / command prix dans frontend absent -valorisation balance SOL en USD absente +calcul de valorisation frontend / f64 absent WalletSession / VIEW / OWNER / secrets inchangés ``` @@ -615,16 +616,60 @@ cargo check --workspace PASS cargo clippy --workspace --all-targets FAIL — desktop_contract.rs + manual_is_multiple_of ``` -Le correctif attendu est strictement mécanique : +`pre.008-fix.001` corrige ces deux défauts mécaniques. Son gate opérateur du `27 août 2026` donne ensuite : ```text -desktop_contract.rs raw strings Rust valides -wallet_balance.rs coefficient.is_multiple_of(10) -version 0.2.12-pre.8.fix.1 -logique moyenne / Off-chain / DTO / frontend inchangée +cargo fmt --all PASS +python3 scripts/audit_rust_workspace_rules.py PASS +python3 scripts/audit_markdown_tables.py README.md ... deltas PASS +cargo check --workspace PASS +cargo clippy --workspace --all-targets PASS +cargo test -p ksp-app-wallet-desk FAIL — 1 canari desktop historique +cargo test --workspace NOT RUN après l'échec ciblé +cargo tauri dev Wallet Desk PASS ``` -Gate opérateur à rejouer après application : +Le test ciblé passe `61` unit tests, `3` tests de composition et `18/19` tests `desktop_contract`. L'unique échec est : + +```text +pre_018_packaged_runtime_bundles_config_resources_and_keeps_wallet_desk_version_coherent +assertion failed: main.contains(packaged_version) +``` + +Le runtime manuel confirme en parallèle que le chemin métier est opérationnel : + +```text +provider_count=8 +observed_provider_count=6 +average_available=true +sol_usd_average_available=true +getBalance succès +cargo tauri dev succès +``` + +Deux écarts restent donc à corriger dans `pre.008-fix.002` : le badge principal est encore figé à `0.2.6`, et la vue Details ne montre pas l'information prix auxiliaire. La demande opérateur précise en outre que l'équivalent USD de la balance doit être visible. + +## 26. Gate `0.2.12-pre.008-fix.002` — équivalent USD et version dynamique + +Le correctif attendu reste dans la responsabilité Wallet condensée de `pre.008` : + +```text +WalletBalanceDto.sol_usd_average conservé +WalletBalanceDto.sol_usd_equivalent ajouté, Option +source de l'équivalent lamports + moyenne du refresh courant +calcul Rust/u128, aucun f64/f32/JS +arrondi équivalent half-up, 8 décimales max +prix auxiliaire indisponible moyenne N.A. + équivalent N.A. +balance SOL autoritative inchangée +Dashboard moyenne + équivalent +Details moyenne + équivalent +badge 0.2.6 statique supprimé +version affichée RuntimeStatusDto.application_version +canari packaging version-neutral, vérifie le binding dynamique +provider_id / URL / credential / command prix Wallet absent +``` + +Gate opérateur à rejouer : ```bash cargo fmt --all @@ -636,4 +681,3 @@ cargo test -p ksp-app-wallet-desk cargo test --workspace (cd crates/ksp-app-wallet-desk && cargo tauri dev) ``` -