π§© Components
SuperSafe Wallet's frontend is built with React 18, organized into a clear component hierarchy with presentational components and screen-based routing.
Overviewβ
Component Organizationβ
src/components/
βββ App.jsx # Main application (1,569 lines)
βββ Dashboard.jsx # Portfolio view
βββ Swap.jsx # Swap interface (~115 lines container)
βββ Settings.jsx # Settings panel
βββ Ecosystem.jsx # Ecosystem explorer
β
βββ screens/ # Full-screen views
β βββ ConnectionRequestScreen.jsx
β βββ TransactionConfirmationScreen.jsx
β βββ SigningConfirmationScreen.jsx
β βββ TypedDataConfirmationScreen.jsx
β βββ NetworkSwitchConfirmationScreen.jsx
β βββ UnsupportedNetworkScreen.jsx
β βββ TransactionSuccessScreen.jsx
β
βββ swap/ # Swap provider panels
β βββ BebopSwapPanel.jsx # Bebop implementation (~1,400 lines)
β βββ RelaySwapPanel.jsx # Relay implementation (~1,288 lines)
β βββ shared/ # Shared utilities
β βββ CompactNetworkSelector.jsx
β βββ RouteVisualization.jsx
β βββ BridgeTimeDisplay.jsx
β βββ GasEstimateDisplay.jsx
β βββ LoadingDots.jsx
β
βββ modals/ # Modal dialogs
β βββ UnlockWalletModal.jsx
β βββ EditWalletModal.jsx
β βββ NetworkConsentModal.jsx
β βββ SignatureModal.jsx
β βββ LoadingModal.jsx
β
βββ settings/ # Settings sections
β βββ SecuritySection.jsx
β βββ WalletsSection.jsx
β βββ NetworkSection.jsx
β βββ TokensSection.jsx
β βββ WalletConnectSection.jsx
β
βββ common/ # Reusable components
βββ Dashboard/
β βββ PortfolioBalanceSection.jsx
β βββ TokensList.jsx
β βββ NFTsSection.jsx
β βββ TokenCardDark.jsx
βββ TokenImage.jsx # Token logo display with fallback
βββ TokenLogo.jsx # Advanced logo with orchestrator
βββ NetworkIcon.jsx # Network/chain logos
App Component (1,569 lines)β
Location: src/App.jsx
Core Responsibilities:
- Screen routing based on URL parameters
- Modal state management
- Connection request handling
- Transaction/signing confirmation
- Network switch consent
Screen Routing:
// Mode detection from URL params
const urlParams = new URLSearchParams(window.location.search);
const mode = urlParams.get('mode');
const screen = urlParams.get('screen');
// Route to appropriate screen
if (screen === 'connection') {
return <ConnectionRequestScreen />;
} else if (screen === 'transaction') {
return <TransactionConfirmationScreen />;
} else if (screen === 'signing') {
return <SigningConfirmationScreen />;
} else if (screen === 'typed_data') {
return <TypedDataConfirmationScreen />;
} else if (screen === 'network_switch') {
return <NetworkSwitchConfirmationScreen />;
} else if (screen === 'unsupported_network') {
return <UnsupportedNetworkScreen />;
} else if (isUnlocked) {
return <Dashboard />;
} else {
return <UnlockWalletModal />;
}
Screen Componentsβ
TransactionConfirmationScreenβ
Location: src/components/screens/TransactionConfirmationScreen.jsx
Enhanced Features (v3.0+):
- β Rich transaction decoding (DEX swaps, ERC-20, NFTs)
- β
Token logos integration via
getTokenLogo() - β Collapsible detail sections (Contract Interaction, Batch Operations, Security, Raw Data)
- β Wei amount detection and formatting
- β "You Send" / "You Receive" prominent display
- β Always-visible Security notice (outside scrollable area)
Architecture:
function TransactionConfirmationScreen({ transaction, decodedTransaction, origin }) {
const [showContractDetails, setShowContractDetails] = useState(false);
const [showBatchOps, setShowBatchOps] = useState(false);
const [showRawData, setShowRawData] = useState(false);
// Extract decoded call information
const decodedCall = decodedTransaction?.decodedCall;
const isSwap = decodedCall?.type?.includes('Swap');
return (
<div className="confirmation-screen">
{/* Main Transaction Block */}
<div className="main-transaction-block">
<NetworkHeader chainId={chainId} />
<OriginLine origin={origin} />
{isSwap && (
<>
{/* You Send - Always Visible */}
<div className="you-send">
<TokenImage address={decodedCall.tokenIn.address} symbol={decodedCall.tokenIn.symbol} />
<span>{formatAmount(decodedCall.amountIn)} {decodedCall.tokenIn.symbol}</span>
</div>
{/* You Receive - Always Visible */}
<div className="you-receive">
<TokenImage address={decodedCall.tokenOut.address} symbol={decodedCall.tokenOut.symbol} />
<span>~{formatAmount(decodedCall.amountOutMin)} {decodedCall.tokenOut.symbol}</span>
</div>
</>
)}
</div>
{/* Collapsible Sections */}
<CollapsibleSection title="Contract Interaction" isOpen={showContractDetails} />
<CollapsibleSection title="Batch Operations" isOpen={showBatchOps} />
<CollapsibleSection title="Raw Data" isOpen={showRawData} />
{/* Security Notice - Always Visible */}
<SecurityNotice origin={origin} warnings={decodedCall?.risks} />
{/* Action Buttons */}
<div className="actions">
<button onClick={onReject}>Reject</button>
<button onClick={onApprove}>Confirm</button>
</div>
</div>
);
}
TypedDataConfirmationScreenβ
Location: src/components/screens/TypedDataConfirmationScreen.jsx
Enhanced Features (v3.0+):
- β PermitSingle (Permit2) rich display
- β PermitBatchWitnessTransferFrom support
- β Unlimited approval detection (MAX_UINT160)
- β Human-readable expiration dates
- β Token logos for approved tokens
- β Collapsible "Additional Details" section
SigningConfirmationScreenβ
Location: src/components/screens/SigningConfirmationScreen.jsx
Enhanced Features (v3.0+):
- β Hex to UTF-8 decoding for personal_sign
- β SIWE (Sign-In With Ethereum) detection
- β Message preview with scroll
- β Collapsible "Raw Message" section
UnsupportedNetworkScreenβ
Location: src/components/screens/UnsupportedNetworkScreen.jsx
Purpose: Display clear error when dApp requests a network SuperSafe doesn't support.
Swap Componentsβ
Unified Panel Architecture (v2.0.0)β
Swap.jsx (~115 lines) - Container/Orchestrator only
const Swap = ({
onTransactionComplete,
preselectedToken,
onClearPreselection,
walletTokensWithBalance,
nativeTokenBalance
}) => {
const [swapProvider, setSwapProvider] = useState('bebop');
const [slippage, setSlippage] = useState(0.5);
return (
<>
<SwapProviderSelector selected={swapProvider} onChange={setSwapProvider} />
<SlippageControl slippage={slippage} onChange={setSlippage} />
{swapProvider === 'relay' ? (
<RelaySwapPanel {...props} slippage={slippage} />
) : (
<BebopSwapPanel {...props} slippage={slippage} />
)}
</>
);
};
BebopSwapPanel.jsx (~1,400 lines) - Complete Bebop implementation
RelaySwapPanel.jsx (~1,288 lines) - Complete Relay.link implementation
Common Componentsβ
TokenLogo Componentβ
Location: src/components/common/TokenLogo.jsx
Features:
- Uses logo orchestrator for intelligent resolution
- In-memory + persistent caching
- Automatic fallback through providers
- Error handling with placeholder
TokenImage Componentβ
Location: src/components/common/TokenImage.jsx
Features:
- Simpler component for basic use cases
- Manual logo URL construction
- Fallback to placeholder
UI/UX Patternsβ
Collapsible Sections Patternβ
Purpose: Improve UX by hiding complex details by default while maintaining full transparency.
Implementation:
function CollapsibleSection({ title, isOpen, onToggle, children }) {
return (
<div className="collapsible-section">
<div className="section-header" onClick={onToggle}>
<h3>{title}</h3>
<span className="chevron">{isOpen ? 'βΌ' : 'βΆ'}</span>
</div>
{isOpen && (
<div className="section-content">
{children}
</div>
)}
</div>
);
}
Philosophy:
- Critical info always visible (You Send, You Receive, Amount, Origin)
- Technical details collapsible (Contract Interaction, Batch Operations, Raw Data)
- Security notice ALWAYS visible (outside scrollable area, below action buttons)
Document Status: β
Current as of November 15, 2025
Code Version: v3.0.0+
Maintenance: Review after major component changes