Skip to main content

🧩 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