Added functionality to display server public IP address for users to configure exchange API whitelists, specifically for Binance integration.
Backend changes (api/server.go):
- Add GET /api/server-ip endpoint requiring authentication
- Implement getPublicIPFromAPI() with fallback to multiple IP services
- Implement getPublicIPFromInterface() for local network interface detection
- Add isPrivateIP() helper to filter private IP addresses
- Import net package for IP address handling
Frontend changes (web/):
- Add getServerIP() API method in api.ts
- Display server IP in ExchangeConfigModal for Binance
- Add IP copy-to-clipboard functionality
- Load and display server IP when Binance exchange is selected
- Add i18n translations (en/zh) for whitelist IP messages:
- whitelistIP, whitelistIPDesc, serverIPAddresses
- copyIP, ipCopied, loadingServerIP
User benefits:
- Simplifies Binance API whitelist configuration
- Shows exact server IP to add to exchange whitelist
- One-click IP copy for convenience
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
- Add 13 translation keys for candidate coins warnings in both English and Chinese
- Update App.tsx to use t() function for all warning text
- Update AITradersPage.tsx to use t() function for signal source warnings
- Ensure proper internationalization for all user-facing messages
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
Merged standalone USDT warning into existing security warning section for cleaner UI.
Changes:
- Removed separate red warning box for USDT
- Added USDT warning as first item in security warning box (conditional on Aster exchange)
- Now shows 4 warnings for Aster: USDT requirement + 3 general security warnings
- Cleaner, more organized warning presentation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added warning message to inform users that Aster only tracks USDT balance, preventing P&L calculation errors from asset price fluctuations.
Why this is important:
- Aster trader only tracks USDT balance (aster_trader.go:453)
- If users use BNB/ETH as margin, price fluctuations will cause:
* Initial balance becomes inaccurate
* P&L statistics will be wrong
* Example: 10 BNB @ $100 = $1000, if BNB drops to $90, real equity is $900 but system still shows $1000
Changes:
- Added asterUsdtWarning translation in both EN and ZH
- Added red warning box below Aster private key field
- Clear message: "Please use USDT as margin currency"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added interactive help icons with tooltips for Aster exchange fields (user, signer, privateKey) to guide users through correct configuration.
Changes:
- Added HelpCircle icon from lucide-react
- Created reusable Tooltip component with hover/click interaction
- Added bilingual help descriptions in translations.ts
- User field: explains main wallet address (login address)
- Signer field: explains API wallet address generation
- Private Key field: clarifies local-only usage, never transmitted
This prevents user confusion and configuration errors when setting up Aster exchange.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Install ESLint 9 with TypeScript and React support
- Install Prettier with custom configuration (no semicolons)
- Add husky and lint-staged for pre-commit hooks
- Configure lint-staged to auto-fix and format on commit
- Relax ESLint rules to avoid large-scale code changes
- Format all existing code with Prettier (no semicolons)
Co-Authored-By: Claude <noreply@anthropic.com>
## Fixes
### 1. Typewriter Component - Missing First Character
- Fix character loss issue where first character of each line was missing
- Add proper state reset logic before starting typing animation
- Extract character before setState to avoid closure issues
- Add setTimeout(0) to ensure state is updated before typing starts
- Change dependency from `lines` to `sanitizedLines` for correct updates
- Use `??` instead of `||` for safer null handling
### 2. Chinese Translation - Leading Spaces
- Remove leading spaces from startupMessages1/2/3 in Chinese translations
- Ensures proper display of startup messages in terminal simulation
### 3. Dynamic GitHub Stats with Animation
- Add useGitHubStats hook to fetch real-time GitHub repository data
- Add useCounterAnimation hook with easeOutExpo easing for smooth number animation
- Display dynamic star count with smooth counter animation (2s duration)
- Display dynamic days count (static, no animation)
- Support bilingual display (EN/ZH) with proper formatting
## Changes
- web/src/components/Typewriter.tsx: Fix first character loss bug
- web/src/i18n/translations.ts: Remove leading spaces in Chinese messages
- web/src/components/landing/HeroSection.tsx: Add dynamic GitHub stats
- web/src/hooks/useGitHubStats.ts: New hook for GitHub API integration
- web/src/hooks/useCounterAnimation.ts: New hook for number animations
Fixes#365🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Redirect to /traders instead of / after successful login/registration
- Make 'Get Started Now' button redirect logged-in users to /traders
- Prevent infinite loop where logged-in users are shown landing page repeatedly
Fixes issue where after login success, clicking "Get Started Now" would
show login modal again instead of entering the main application.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
## Problem
When editing trader configuration, if `system_prompt_template` was set to an empty string (""), the UI would incorrectly treat it as falsy and overwrite it with 'default', losing the user's selection.
**Root cause:**
```tsx
if (traderData && !traderData.system_prompt_template) {
// ❌ This triggers for both undefined AND empty string ""
setFormData({ system_prompt_template: 'default' });
}
```
JavaScript falsy values that trigger `!` operator:
- `undefined` ✅ Should trigger default
- `null` ✅ Should trigger default
- `""` ❌ Should NOT trigger (user explicitly chose empty)
- `false`, `0`, `NaN` (less relevant here)
## Solution
Change condition to explicitly check for `undefined`:
```tsx
if (traderData && traderData.system_prompt_template === undefined) {
// ✅ Only triggers for truly missing field
setFormData({ system_prompt_template: 'default' });
}
```
## Impact
- ✅ Empty string selections are preserved
- ✅ Legacy data (undefined) still gets default value
- ✅ User's explicit choices are respected
- ✅ No breaking changes to existing functionality
## Testing
- ✅ Code compiles
- ⚠️ Requires manual UI testing:
- [ ] Edit trader with empty system_prompt_template
- [ ] Verify it doesn't reset to 'default'
- [ ] Create new trader → should default to 'default'
- [ ] Edit old trader (undefined field) → should default to 'default'
## Code Changes
```
web/src/components/TraderConfigModal.tsx:
- Line 99: Changed !traderData.system_prompt_template → === undefined
```
Enable automatic wallet address generation from private key for Hyperliquid
exchange, simplifying user onboarding and reducing configuration errors.
Backend Changes (trader/hyperliquid_trader.go):
- Import crypto/ecdsa package for ECDSA public key operations
- Enable wallet address auto-generation when walletAddr is empty
- Use crypto.PubkeyToAddress() to derive address from private key
- Add logging for both auto-generated and manually provided addresses
Frontend Changes (web/src/components/AITradersPage.tsx):
- Remove wallet address required validation (only private key required)
- Update button disabled state to only check private key
- Add "Optional" label to wallet address field
- Add dynamic placeholder with bilingual hint
- Show context-aware helper text based on input state
- Remove HTML required attribute from input field
Translation Updates (web/src/i18n/translations.ts):
- Add 'optional' translation (EN: "Optional", ZH: "可选")
- Add 'hyperliquidWalletAddressAutoGenerate' translation
EN: "Leave blank to automatically generate wallet address from private key"
ZH: "留空将自动从私钥生成钱包地址"
Benefits:
✅ Simplified UX - Users only need to provide private key
✅ Error prevention - Auto-generated address always matches private key
✅ Backward compatible - Manual address input still supported
✅ Better UX - Clear visual indicators for optional fields
Technical Details:
- Uses Ethereum standard ECDSA public key to address conversion
- Implementation was already present but commented out (lines 37-43)
- No database schema changes required (hyperliquid_wallet_addr already nullable)
- Fallback behavior: manual input > auto-generation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add NOFX watermark to ComparisonChart (competition page)
- Add NOFX watermark to EquityChart (dashboard page)
- Fix empty state handling and internationalization in CompetitionPage
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
The chart was not showing data because the API response format changed.
Fixed the calculation of PnL percentage by computing it from total_pnl
and balance values (initial_balance = balance - total_pnl).
Now the AI competition chart should properly display performance comparison data.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Removed test script from package.json
- Removed testing dependencies (@testing-library/react, vitest, jsdom)
- Deleted test directory and vitest.config.ts
- Updated package-lock.json to reflect changes
- Build still works perfectly without test dependencies
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Removed App.test.tsx and AITradersPage.test.tsx that were causing TypeScript build issues and are not currently in use.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Removed unused 'Zap' import from App.tsx that was causing build failure.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Match main app layout with proven working /competition route layout:
- Use px-6 py-6 pt-24 padding (same as /competition route)
- Ensures HeaderBar doesn't overlap content on /traders and /dashboard pages
- Provides consistent 6rem (96px) top clearance for fixed positioned HeaderBar
- Removes responsive padding variants that differed from competition page
This fixes header overlap issues across all main application routes.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replace the inline header implementation in main app with HeaderBar component to match landing page:
- Remove duplicate inline header code (168 lines)
- Use HeaderBar component for all main app pages like landing page does
- Ensure consistent header design across all routes (/competition, /traders, /dashboard)
- Maintain proper onPageChange navigation handling
- Keep all header functionality (user info, admin mode, language toggle, logout)
This fixes the header inconsistency where different pages used different header implementations.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Frontend changes to ensure equity-history-batch API only requests data for top 5 performers:
- Modify CompetitionPage to pass only top 5 traders to ComparisonChart component
- Update API comments to reflect the change from top 10 to top 5
- Optimize chart performance by reducing data volume and API calls
This ensures the performance comparison chart shows only the most relevant traders while improving load times.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>