From fb4f27a88fd87df92c24b9675e1599e0fc8d6138 Mon Sep 17 00:00:00 2001 From: 2ro <17595647+2ro@users.noreply.github.com> Date: Sun, 14 Jun 2026 18:08:23 -0400 Subject: [PATCH] Build 75: no pairing by default; price back over the mixnet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Pairing defaults to Off on first run: no conversion is shown anywhere and no price request leaves the device until the user opts into a pairing. Off is a picker option and the choice persists. - The rate fetch goes back over the Nym mixnet (reverting Build 71's clearnet route) — it's opt-in and infrequent, so it stays private and doesn't get in the way of slatepacks. CoinGecko's free-tier rate limit (shared exit IP) rules out live/1s polling, so it keeps the slow cache. - Small note on the Pairing page that rates fetch over the mixnet. --- src/gui/views/goblin/mod.rs | 9 +++++++++ src/http/price.rs | 25 ++++++++++++------------- src/settings/config.rs | 7 +++++-- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/gui/views/goblin/mod.rs b/src/gui/views/goblin/mod.rs index 29841e0..59376c7 100644 --- a/src/gui/views/goblin/mod.rs +++ b/src/gui/views/goblin/mod.rs @@ -2226,6 +2226,15 @@ impl GoblinWalletView { } } }); + ui.add_space(10.0); + ui.label( + RichText::new( + "Rates fetch over the Nym mixnet, only while a pairing is on — \ + off means no rate request leaves your device.", + ) + .font(FontId::new(12.0, fonts::regular())) + .color(t.text_dim), + ); ui.add_space(16.0); }); } diff --git a/src/http/price.rs b/src/http/price.rs index 0ea45bf..8cbfd57 100644 --- a/src/http/price.rs +++ b/src/http/price.rs @@ -12,15 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! GRIN price preview, cached per currency. The rate is non-sensitive metadata -//! (no payment info), so — like the update check, and like upstream Grim — it is -//! fetched direct over HTTPS rather than waiting on the mixnet, keeping the -//! preview prompt. Payments, relays and identity stay mixnet-only. +//! GRIN price preview, cached per currency. Off by default (no pairing → no +//! fetch); only once the user opts into a pairing is the rate fetched — and it +//! goes over the Nym mixnet like everything else, never the clear net. The rate +//! barely moves and CoinGecko's free tier rate-limits frequent polling (the +//! shared exit IP all the more), so it refreshes on a slow cache, not live. use lazy_static::lazy_static; use parking_lot::RwLock; use std::collections::{HashMap, HashSet}; -use std::time::{Duration, SystemTime, UNIX_EPOCH}; +use std::time::{SystemTime, UNIX_EPOCH}; + +use crate::nym; /// Cache refresh interval (seconds). const REFRESH_SECS: i64 = 300; @@ -91,20 +94,16 @@ fn trigger_refresh(vs: String) { }); } -/// Fetch the GRIN/`vs` rate from CoinGecko, direct over HTTPS. +/// Fetch the GRIN/`vs` rate from CoinGecko over the Nym mixnet. async fn fetch_rate(vs: &str) -> Option { let url = format!( "https://api.coingecko.com/api/v3/simple/price?ids=grin&vs_currencies={}", vs ); // CoinGecko rejects requests without a User-Agent (403). A static, - // non-identifying UA. - let client = reqwest::Client::builder() - .user_agent("goblin-wallet") - .timeout(Duration::from_secs(20)) - .build() - .ok()?; - let body = client.get(&url).send().await.ok()?.text().await.ok()?; + // non-identifying UA is fine over the mixnet. + let headers = vec![("User-Agent".to_string(), "goblin-wallet".to_string())]; + let body = nym::http_request("GET", url, None, headers).await?; let parsed: Option = serde_json::from_str::(&body) .ok() .and_then(|doc| doc.get("grin")?.get(vs)?.as_f64()); diff --git a/src/settings/config.rs b/src/settings/config.rs index 6aa0860..d0d2909 100644 --- a/src/settings/config.rs +++ b/src/settings/config.rs @@ -458,9 +458,12 @@ impl AppConfig { return p; } } + // No pairing chosen yet → off by default: no conversion is shown anywhere + // and no price is fetched until the user opts into a pairing. (A legacy + // `fiat_preview = true` still defaults to USD for existing users.) match r_config.fiat_preview { - Some(false) => Pairing::Off, - _ => Pairing::Usd, + Some(true) => Pairing::Usd, + _ => Pairing::Off, } }