BubbleNansen is a web application that visualizes the top holders of any token and their counterparty connections using an interactive bubble/network diagram powered by the Nansen API. It helps users understand token distribution, identify whale clusters, and explore transaction relationships between major holders.
The core functionality is implemented and working:
- Top 20 holders visualization
- Counterparty connections on click
- Multi-chain support
- Configurable settings
- Nansen branding
| Component | Technology |
|---|---|
| Frontend | React 18 + TypeScript |
| Build Tool | Vite |
| Visualization | D3.js (force-directed graph) |
| Styling | Tailwind CSS |
| Theme | Dark mode (crypto aesthetic) |
| API | Nansen API (Token God Mode) |
| HTTP Client | Axios + React Query |
Multi-chain support:
- Ethereum Mainnet
- BNB Smart Chain (BSC)
- Polygon
- Arbitrum
- Optimism
- Base
- Avalanche C-Chain
- Solana
- Contract address input field
- Chain selector dropdown (8 chains)
- Address validation (EVM and Solana formats)
- URL parameter support (
?token=0x...&chain=ethereum)
- Fetches top 20 token holders from Nansen API
- Displays holders as bubbles in a force-directed graph
- Bubble size proportional to token holdings (sqrt scale for area)
- Color coding by wallet type:
- Exchange wallets: Amber/orange
- DeFi protocols: Blue
- Funds/VCs: Violet
- Whales: Indigo
- Contracts: Cyan
- Unknown: Gray
- Wallet name labels displayed on nodes
- Hover tooltips with balance and value details
- Click any holder to fetch their counterparties
- Draws edges between holders and their counterparties
- Edge styling: dashed cyan lines
- Counterparty nodes have dashed borders to distinguish them
- "Expand All" button to fetch counterparties for all holders
- Progress bar during bulk expansion
- Max counterparties per holder (5, 10, 15, 20, 30)
- Time window for counterparty data (7d to 1 year)
- Settings apply to new counterparty lookups
- Holder list sorted by balance
- Click to select and fetch counterparties
- Visual indicator for expanded holders
- Selected holder details panel
+------------------------------------------------------------------+
| [Nansen Logo] [Chain ▼] [Contract Address Input] [Explore] |
+------------------------------------------------------------------+
| | |
| | Settings (collapsible) |
| | - Max Counterparties |
| BUBBLE MAP CANVAS | - Time Window |
| (D3 Force-Directed Graph) | - [Expand All] |
| | |
| | Top Holders List |
| | 1. Address | Balance |
| | 2. Address | Balance |
| | ... |
| | |
| | Selected Holder |
| | Details Panel |
+------------------------------------------------------------------+
- Background:
#0a0a0f(near black) - Surface:
#13131a(dark gray) - Border:
#1e1e2e(subtle border) - Primary:
#6366f1(indigo/purple) - Accent:
#22d3ee(cyan) - Nansen Green:
#00FFA7(buttons)
-
Token Holders (
/api/v1/tgm/holders)- POST request with chain, token_address, pagination
- Returns top holders with balances, labels, value_usd
- Ordered by
token_amountdescending
-
Address Counterparties (
/api/v1/profiler/address/counterparties)- POST request with chain, address, date range
- Returns counterparty addresses with interaction counts, volumes
- Used to build connection graph
- Base URL proxied through Vite:
/api/nansen→https://api.nansen.ai - API key sent via
apiKeyheader - Environment variable:
VITE_NANSEN_API_KEY
src/
├── components/
│ └── BubbleMap.tsx # D3 force-directed graph visualization
├── services/
│ └── nansen.ts # Nansen API client
├── types/
│ └── index.ts # TypeScript type definitions
├── App.tsx # Main application component
├── main.tsx # Entry point
└── index.css # Tailwind CSS styles
forceCenter- Centers the graphforceManyBody- Node repulsion (stronger for holders, weaker for counterparties)forceCollide- Prevents bubble overlapforceLink- Connection springs between linked nodes
- useRef for callbacks to prevent D3 re-renders on state changes
- useMemo for stable node array references
- Separate useEffect for selection styling vs graph rebuilding
Vite proxy configuration in vite.config.ts:
proxy: {
'/api/nansen': {
target: 'https://api.nansen.ai',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api\/nansen/, ''),
},
}- Automatic clustering of related wallets
- Visual grouping (convex hull backgrounds)
- Cluster statistics and labels
- Expand/collapse clusters
- Transaction history panel for selected wallet
- Animated flow visualization
- Time-based filtering
- Loading skeletons
- Keyboard shortcuts
- Mobile responsive design
- Export as image
# Install dependencies
npm install
# Set up environment
cp .env.example .env
# Add your VITE_NANSEN_API_KEY
# Run development server
npm run dev
# Build for production
npm run buildUse well-known tokens for testing:
- USDC on Ethereum:
0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 - USDT on Ethereum:
0xdac17f958d2ee523a2206206994597c13d831ec7