7. User Experience7.4 Confidence Dashboard

7.4. Confidence Dashboard

The Confidence Dashboard is the user-facing manifestation of Fhenix-FairMarket’s core privacy philosophy: “Trust in proof, not in intermediaries.” Traditional auction interfaces expose bid values, participant addresses, and ranking data—information that, in a sealed-bid context, fundamentally undermines cryptographic guarantees and enables strategic manipulation.

Version 2.0 resolves this through Progressive Disclosure: a design pattern that displays only safe, aggregated, or state-gated metrics until cryptographic settlement is complete. Users gain confidence through transparency about process—not through exposure of sensitive data—while the protocol maintains mathematical privacy end-to-end.

Core Design Principles

PrincipleTechnical Implementation
Zero Plaintext DisplayNo numeric bid values, winner addresses, or decrypted data are shown before FINALIZED or VOIDED state. Enforced via component-level guards and CI lint rules.
State-Gated VisibilityMetrics dynamically adapt to AuctionState: ACTIVE shows encryption status; RESOLVING shows processing progress; FINALIZED reveals outcome.
Terminology AbstractionTechnical terms (FHE, CoFHE, AVS) are replaced with user-centric language ( Protected Bid, ️ Sealed Vault, Network Verified).
Real-Time WebSocket SyncDashboard subscribes to contract events (BidPlaced, AuctionFinalized) via wagmi/viem for sub-2-second latency updates without polling.
Accessibility ComplianceAll metrics include ARIA labels, color-blind safe palettes, and screen-reader optimized text alternatives per WCAG 2.1 AA.

️ Technical Implementation

1. Component Architecture (ConfidenceDashboard.tsx)

The dashboard is a state-aware React component that conditionally renders metrics based on auction state and user role.

// packages/frontend/src/app/auction/[id]/components/ConfidenceDashboard.tsx
'use client';
 
import { useAuctionState } from '@lib/hooks/useAuctionState';
import { AuctionState } from '@lib/contracts/types';
import { MetricCard } from '@components/ui/MetricCard';
 
export function ConfidenceDashboard({ auctionId }: { auctionId: string }) {
 const { state, activeBids, timeRemaining, encryptionStatus, isSeller, isWinner } = useAuctionState(auctionId);
 
 return (
 <div className="grid grid-cols-1 md:grid-cols-3 gap-4" role="region" aria-label="Auction Confidence Metrics">
 
 {/* Always Visible: Process Transparency */}
 <MetricCard 
 label="Sealed Bids" 
 value={activeBids} 
 icon=""
 tooltip="Encrypted bids submitted. Values remain hidden until settlement."
 />
 
 <MetricCard 
 label="Time Until Reveal" 
 value={formatTime(timeRemaining)} 
 icon="️"
 tooltip="Official decryption window opens at this time."
 />
 
 {/* State-Gated: Encryption Status */}
 {state === AuctionState.ACTIVE && (
 <MetricCard 
 label="Your Bid Status" 
 value={encryptionStatus} 
 icon="️"
 variant={encryptionStatus === 'Confirmed' ? 'success' : 'pending'}
 />
 )}
 
 {/* State-Gated: Processing Status */}
 {state === AuctionState.RESOLVING && (
 <MetricCard 
 label="Settlement Progress" 
 value=" CoFHE Processing" 
 icon="️"
 tooltip="Encrypted comparison in progress. Zero plaintext exposure."
 />
 )}
 
 {/* State-Gated: Final Outcome (Winner/Seller Only) */}
 {state === AuctionState.FINALIZED && (isSeller || isWinner) && (
 <MetricCard 
 label="Result" 
 value={isWinner ? ' You Won' : ' Winner Declared'} 
 icon={isWinner ? '' : ''}
 variant="success"
 />
 )}
 
 {/* Emergency State: Auto-Recovery */}
 {state === AuctionState.VOIDED && (
 <MetricCard 
 label="Status" 
 value="️ Auto-Refund Triggered" 
 icon=""
 variant="warning"
 tooltip="Network delay detected. Full liquidity recovery available via claimRefund()."
 />
 )}
 </div>
 );
}

2. Terminology Mapping & Progressive Disclosure

Technical complexity is translated into trust-building, non-leaking user language.

Technical TermUser-Facing LanguageVisibility Rule
FHE EncryptionBid ProtectedAlways shown during ACTIVE
CoFHE Processing️ Sealed Vault ActiveShown during RESOLVING
AVS VerificationVerified by NetworkShown during FINALIZED
Dynamic Timeout️ Auto-refund triggeredShown only during VOIDED
Ciphertext HashEncrypted & ConfirmedNever shows raw hex
FHE.lte SolvencyFunds VerifiedAbstracted; never shows balance
SlashedPot DistributionCompensation PoolShown only during CANCELLED

3. Real-Time State Subscription (useAuctionState.ts)

The hook manages WebSocket event subscriptions and local state caching for sub-2-second dashboard updates.

// packages/frontend/src/lib/hooks/useAuctionState.ts
import { useEffect, useState } from 'react';
import { usePublicClient, useWatchContractEvent } from 'wagmi';
import { fairMarketAbi } from '@lib/contracts/abi';
 
export function useAuctionState(auctionId: string) {
 const [state, setState] = useState<AuctionState>(AuctionState.CREATED);
 const [activeBids, setActiveBids] = useState(0);
 const [timeRemaining, setTimeRemaining] = useState<number>();
 
 const client = usePublicClient();
 
 // Initial fetch
 useEffect(() => {
 const fetchState = async () => {
 const [auctionState, bidCount, endTime] = await client.multicall({
 contracts: [
 { address: CONTRACT_ADDRESS, abi: fairMarketAbi, functionName: 'getAuctionState', args: [auctionId] },
 { address: CONTRACT_ADDRESS, abi: fairMarketAbi, functionName: 'getBidCount', args: [auctionId] },
 { address: CONTRACT_ADDRESS, abi: fairMarketAbi, functionName: 'getEndTime', args: [auctionId] },
]
 });
 setState(auctionState.result as AuctionState);
 setActiveBids(Number(bidCount.result));
 setTimeRemaining(Number(endTime.result) - Date.now()/1000);
 };
 fetchState();
 }, [auctionId, client]);
 
 // Real-time event subscriptions
 useWatchContractEvent({
 address: CONTRACT_ADDRESS,
 abi: fairMarketAbi,
 eventName: 'BidPlaced',
 args: { auctionId: BigInt(auctionId) },
 onLogs: (logs) => setActiveBids(prev => prev + logs.length)
 });
 
 useWatchContractEvent({
 address: CONTRACT_ADDRESS,
 abi: fairMarketAbi,
 eventName: 'AuctionFinalized',
 args: { auctionId: BigInt(auctionId) },
 onLogs: () => setState(AuctionState.FINALIZED)
 });
 
 return { state, activeBids, timeRemaining, encryptionStatus: deriveEncryptionStatus(state) };
}

Dashboard Data Flow

️ Security & Privacy Guarantees

  1. Zero Information Leakage: The dashboard never renders plaintext bid values, winner addresses, or decrypted settlement data before cryptographic finality. Component-level guards and CI lint rules enforce this at build time.
  2. State-Gated Access Control: Sensitive metrics (e.g., “You Won”) are only visible to authenticated users with verified roles (isSeller, isWinner), preventing unauthorized information disclosure.
  3. Timing Attack Resistance: By displaying aggregated counts (activeBids) rather than individual bid timestamps or values, the dashboard neutralizes inference attacks based on UI update patterns.
  4. Accessibility by Design: All metrics include ARIA labels, keyboard navigation support, and color-blind safe palettes, ensuring trust transparency is inclusive and compliant with WCAG 2.1 AA.
  5. Offline Resilience: Cached state persists via Zustand store during network drops, preventing UI flicker or data loss while maintaining privacy boundaries.

Audit Gate Compliance (P0)

Progression through Phase 5 is strictly blocked until all P0 items pass:

  • [] Zero Plaintext Rendering: CI lint rules fail the build if any component attempts to display numeric bid values, winner addresses, or decrypted data before FINALIZED/VOIDED state.
  • [] State-Gated Visibility: Unit tests confirm that ConfidenceDashboard conditionally renders metrics exactly per AuctionState transition rules.
  • [] Terminology Abstraction: All technical terms (FHE, CoFHE, AVS) are mapped to user-facing language via a centralized terminology.ts dictionary; no raw terms appear in UI strings.
  • [] WebSocket Latency: Dashboard updates reflect on-chain events within <2s under normal network conditions; fallback polling activates on WebSocket failure.
  • [] Accessibility Compliance: Automated axe-core scans confirm WCAG 2.1 AA compliance for all dashboard variants (light/dark mode, mobile/desktop).
  • [] Role-Based Access: isSeller/isWinner checks are enforced server-side via signature verification; client-side guards are defense-in-depth only.

Unresolved Points & Explicit Gaps

Gap / Unresolved PointImpactCurrent StatusRecommended Action
Multi-Language SupportDashboard strings currently assume English/Arabic. Global accessibility requires i18n.i18n framework not initialized in Phase 5 specs.Integrate next-i18next and translation files for top 5 languages before Mainnet.
Custom Metric ConfigurationCan DAO governance adjust which metrics are displayed or their visibility rules?Not supported; metrics are hardcoded in component.Design a governance-controlled DashboardConfig.sol for dynamic metric rules in v2.1.
Mobile-Specific LayoutDesktop-centric grid may not optimize for small-screen auction participation.Tailwind responsive classes exist but no mobile-specific UX testing.Add mobile E2E tests and viewport-specific component variants in Phase 5 refinement.
Historical Data AccessCan users view past auction metrics (e.g., “How many bids did I place last month?”)?No historical dashboard or analytics layer implemented.Build a privacy-preserving analytics module using zero-knowledge proofs for aggregate history in v2.2.

Fact vs. Analysis Distinction: Zero-plaintext rendering, state-gated visibility, terminology abstraction, WebSocket latency targets, and accessibility compliance are verified facts from Phase 5 Sub-Tasks Matrix (Task 5.4) and the README.md UX 2.0 principles. i18n, configurable metrics, mobile optimization, and historical analytics are unresolved UX enhancements requiring explicit definition before Mainnet launch.


Next Steps