diff --git a/apps/web/next-env.d.ts b/apps/web/next-env.d.ts
new file mode 100644
index 0000000..40c3d68
--- /dev/null
+++ b/apps/web/next-env.d.ts
@@ -0,0 +1,5 @@
+///
+///
+
+// NOTE: This file should not be edited
+// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
diff --git a/apps/web/package.json b/apps/web/package.json
index 59a5f23..9e6f4a7 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -10,10 +10,23 @@
"dependencies": {
"@wtfx/types": "workspace:*",
"@wtfx/api-client": "workspace:*",
+ "@wtfx/contracts": "workspace:*",
"@wtfx/ui": "workspace:*",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"next": "^14.2.4",
- "ethers": "^6.13.0"
+ "ethers": "^6.13.0",
+ "lucide-react": "^0.395.0",
+ "clsx": "^2.1.1",
+ "tailwind-merge": "^2.3.0"
+ },
+ "devDependencies": {
+ "@types/node": "^20.14.2",
+ "@types/react": "^18.3.3",
+ "@types/react-dom": "^18.3.0",
+ "autoprefixer": "^10.4.19",
+ "postcss": "^8.4.38",
+ "tailwindcss": "^3.4.4",
+ "typescript": "^5.4.5"
}
-}
\ No newline at end of file
+}
diff --git a/apps/web/postcss.config.js b/apps/web/postcss.config.js
new file mode 100644
index 0000000..12a703d
--- /dev/null
+++ b/apps/web/postcss.config.js
@@ -0,0 +1,6 @@
+module.exports = {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+};
diff --git a/apps/web/src/app/globals.css b/apps/web/src/app/globals.css
new file mode 100644
index 0000000..1e42f62
--- /dev/null
+++ b/apps/web/src/app/globals.css
@@ -0,0 +1,10 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+body {
+ background-color: #090A0F;
+ color: #F3F4F6;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
+ overflow-x: hidden;
+}
diff --git a/apps/web/src/app/layout.tsx b/apps/web/src/app/layout.tsx
new file mode 100644
index 0000000..a10ada8
--- /dev/null
+++ b/apps/web/src/app/layout.tsx
@@ -0,0 +1,21 @@
+import './globals.css';
+import React from 'react';
+
+export const metadata = {
+ title: 'WTFX | Next-Gen Prediction Market & Liquidity Protocol',
+ description: 'Ultra-low latency prediction markets powered by Power LDA Bonding Curves',
+};
+
+export default function RootLayout({
+ children,
+}: {
+ children: React.ReactNode;
+}) {
+ return (
+
+
+ {children}
+
+
+ );
+}
diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx
new file mode 100644
index 0000000..2adc890
--- /dev/null
+++ b/apps/web/src/app/page.tsx
@@ -0,0 +1,57 @@
+'use client';
+
+import React, { useState } from 'react';
+import { Web3Provider } from '../context/Web3Context';
+import { WebNavbar } from '../components/WebNavbar';
+import { MarketExplore, MarketItem } from '../features/explore/MarketExplore';
+import { TradingTerminal } from '../features/trading/TradingTerminal';
+import { PortfolioView } from '../features/portfolio/PortfolioView';
+
+const DEFAULT_MARKET: MarketItem = {
+ id: 'm-1',
+ marketAddress: '0xc0E24E152771C588B21AEB654b30B1cBAf381c1a',
+ title: 'Will Bitcoin break above $120,000 before end of Q4 2026?',
+ category: 'Crypto',
+ tier: 1,
+ outcomes: [
+ { label: 'YES', price: 0.68, percentage: 68 },
+ { label: 'NO', price: 0.32, percentage: 32 }
+ ],
+ poolLiquidity: 1250000,
+ volume24h: 384000,
+ endTime: '2026-12-31',
+ status: 'ACTIVE'
+};
+
+export default function WebApp() {
+ const [activeTab, setActiveTab] = useState('explore');
+ const [selectedMarket, setSelectedMarket] = useState(DEFAULT_MARKET);
+
+ const handleSelectMarket = (m: MarketItem) => {
+ setSelectedMarket(m);
+ setActiveTab('trade');
+ };
+
+ return (
+
+
+
+
+
+ {activeTab === 'explore' && }
+ {activeTab === 'trade' && }
+ {activeTab === 'portfolio' && }
+
+
+
+
+
+ );
+}
diff --git a/apps/web/src/components/WebNavbar.tsx b/apps/web/src/components/WebNavbar.tsx
new file mode 100644
index 0000000..7afebca
--- /dev/null
+++ b/apps/web/src/components/WebNavbar.tsx
@@ -0,0 +1,101 @@
+import React from 'react';
+import { useWeb3 } from '../context/Web3Context';
+import { Wallet, TrendingUp, Compass, PieChart, ShieldAlert, CheckCircle2 } from 'lucide-react';
+
+interface NavbarProps {
+ activeTab: string;
+ setActiveTab: (tab: string) => void;
+}
+
+export const WebNavbar: React.FC = ({ activeTab, setActiveTab }) => {
+ const { account, wusdBalance, isCorrectNetwork, connectWallet, switchNetwork } = useWeb3();
+
+ const navs = [
+ { id: 'explore', label: '🔥 市场探索', icon: Compass },
+ { id: 'trade', label: '⚡ 交易终端', icon: TrendingUp },
+ { id: 'portfolio', label: '💼 我的持仓与账本', icon: PieChart },
+ ];
+
+ return (
+
+ );
+};
diff --git a/apps/web/src/context/Web3Context.tsx b/apps/web/src/context/Web3Context.tsx
new file mode 100644
index 0000000..e829a3f
--- /dev/null
+++ b/apps/web/src/context/Web3Context.tsx
@@ -0,0 +1,181 @@
+import React, { createContext, useContext, useState, useEffect } from 'react';
+import { ethers } from 'ethers';
+import { DEPLOYMENTS, ABIS, ROBINHOOD_TESTNET_CHAIN } from '@wtfx/contracts';
+
+interface Web3ContextType {
+ account: string | null;
+ provider: ethers.BrowserProvider | null;
+ signer: ethers.Signer | null;
+ chainId: number | null;
+ isCorrectNetwork: boolean;
+ wusdBalance: string;
+ connectWallet: () => Promise;
+ switchNetwork: () => Promise;
+ refreshBalance: () => Promise;
+ getMarketContract: (address: string) => ethers.Contract | null;
+ getCollateralContract: () => ethers.Contract | null;
+}
+
+const Web3Context = createContext({
+ account: null,
+ provider: null,
+ signer: null,
+ chainId: null,
+ isCorrectNetwork: false,
+ wusdBalance: '0',
+ connectWallet: async () => {},
+ switchNetwork: async () => {},
+ refreshBalance: async () => {},
+ getMarketContract: () => null,
+ getCollateralContract: () => null,
+});
+
+export const Web3Provider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
+ const [account, setAccount] = useState(null);
+ const [provider, setProvider] = useState(null);
+ const [signer, setSigner] = useState(null);
+ const [chainId, setChainId] = useState(null);
+ const [wusdBalance, setWusdBalance] = useState('0');
+
+ const isCorrectNetwork = chainId === ROBINHOOD_TESTNET_CHAIN.id;
+
+ const refreshBalance = async () => {
+ if (!account || !provider) return;
+ try {
+ const collateral = new ethers.Contract(
+ DEPLOYMENTS.robinhoodTestnet.contracts.collateral,
+ ABIS.MockERC20,
+ provider
+ );
+ const bal = await collateral.balanceOf(account);
+ setWusdBalance(ethers.formatUnits(bal, 18));
+ } catch (err) {
+ console.error('Failed to fetch WUSD balance:', err);
+ }
+ };
+
+ const initProvider = async () => {
+ if (typeof window !== 'undefined' && (window as any).ethereum) {
+ const browserProvider = new ethers.BrowserProvider((window as any).ethereum);
+ setProvider(browserProvider);
+ try {
+ const network = await browserProvider.getNetwork();
+ setChainId(Number(network.chainId));
+ const accounts = await browserProvider.listAccounts();
+ if (accounts.length > 0) {
+ setAccount(accounts[0].address);
+ setSigner(await browserProvider.getSigner());
+ }
+ } catch (err) {
+ console.error('Init web3 error:', err);
+ }
+
+ (window as any).ethereum.on('accountsChanged', async (accs: string[]) => {
+ if (accs.length > 0) {
+ setAccount(accs[0]);
+ setSigner(await browserProvider.getSigner());
+ } else {
+ setAccount(null);
+ setSigner(null);
+ }
+ });
+
+ (window as any).ethereum.on('chainChanged', (cId: string) => {
+ setChainId(parseInt(cId, 16));
+ window.location.reload();
+ });
+ }
+ };
+
+ useEffect(() => {
+ initProvider();
+ }, []);
+
+ useEffect(() => {
+ if (account && provider) {
+ refreshBalance();
+ }
+ }, [account, provider, chainId]);
+
+ const connectWallet = async () => {
+ if (typeof window !== 'undefined' && (window as any).ethereum) {
+ try {
+ const browserProvider = new ethers.BrowserProvider((window as any).ethereum);
+ await browserProvider.send('eth_requestAccounts', []);
+ const currentSigner = await browserProvider.getSigner();
+ const address = await currentSigner.getAddress();
+ const network = await browserProvider.getNetwork();
+ setProvider(browserProvider);
+ setSigner(currentSigner);
+ setAccount(address);
+ setChainId(Number(network.chainId));
+ } catch (err) {
+ console.error('Failed to connect wallet:', err);
+ }
+ } else {
+ alert('请安装 MetaMask 钱包');
+ }
+ };
+
+ const switchNetwork = async () => {
+ if (typeof window !== 'undefined' && (window as any).ethereum) {
+ const hexChainId = '0x' + ROBINHOOD_TESTNET_CHAIN.id.toString(16);
+ try {
+ await (window as any).ethereum.request({
+ method: 'wallet_switchEthereumChain',
+ params: [{ chainId: hexChainId }],
+ });
+ } catch (switchError: any) {
+ if (switchError.code === 4902) {
+ await (window as any).ethereum.request({
+ method: 'wallet_addEthereumChain',
+ params: [
+ {
+ chainId: hexChainId,
+ chainName: ROBINHOOD_TESTNET_CHAIN.name,
+ rpcUrls: ROBINHOOD_TESTNET_CHAIN.rpcUrls.default.http,
+ nativeCurrency: ROBINHOOD_TESTNET_CHAIN.nativeCurrency,
+ },
+ ],
+ });
+ }
+ }
+ }
+ };
+
+ const getMarketContract = (address: string) => {
+ if (!provider) return null;
+ return new ethers.Contract(address, ABIS.WTFMarketV2, signer || provider);
+ };
+
+ const getCollateralContract = () => {
+ if (!provider) return null;
+ return new ethers.Contract(
+ DEPLOYMENTS.robinhoodTestnet.contracts.collateral,
+ ABIS.MockERC20,
+ signer || provider
+ );
+ };
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const useWeb3 = () => useContext(Web3Context);
diff --git a/apps/web/src/features/explore/MarketExplore.tsx b/apps/web/src/features/explore/MarketExplore.tsx
new file mode 100644
index 0000000..c07db72
--- /dev/null
+++ b/apps/web/src/features/explore/MarketExplore.tsx
@@ -0,0 +1,202 @@
+import React, { useState } from 'react';
+import { Sparkles, TrendingUp, Flame, CheckCircle, Clock, Search, ArrowUpRight } from 'lucide-react';
+
+export interface MarketItem {
+ id: string;
+ marketAddress: string;
+ title: string;
+ category: string;
+ tier: number;
+ outcomes: { label: string; price: number; percentage: number }[];
+ poolLiquidity: number;
+ volume24h: number;
+ endTime: string;
+ status: 'ACTIVE' | 'RESOLVED' | 'FINALISED';
+}
+
+const MOCK_FEATURED_MARKETS: MarketItem[] = [
+ {
+ id: 'm-1',
+ marketAddress: '0xc0E24E152771C588B21AEB654b30B1cBAf381c1a',
+ title: 'Will Bitcoin break above $120,000 before end of Q4 2026?',
+ category: 'Crypto',
+ tier: 1,
+ outcomes: [
+ { label: 'YES', price: 0.68, percentage: 68 },
+ { label: 'NO', price: 0.32, percentage: 32 }
+ ],
+ poolLiquidity: 1250000,
+ volume24h: 384000,
+ endTime: '2026-12-31',
+ status: 'ACTIVE'
+ },
+ {
+ id: 'm-2',
+ marketAddress: '0x2Aeca49669e9E4E6CdCe46A1bc9bf136765A4f75',
+ title: 'Ethereum Layer-2 Total TVL to reach $50 Billion in 2026?',
+ category: 'Crypto',
+ tier: 2,
+ outcomes: [
+ { label: 'YES', price: 0.81, percentage: 81 },
+ { label: 'NO', price: 0.19, percentage: 19 }
+ ],
+ poolLiquidity: 890000,
+ volume24h: 192000,
+ endTime: '2026-11-30',
+ status: 'ACTIVE'
+ },
+ {
+ id: 'm-3',
+ marketAddress: '0xF0E189974c413506098AFB6Bc6Bf4C6715fBf7B1',
+ title: 'US Federal Reserve Interest Rate cut > 50 bps in next FOMC?',
+ category: 'Macro',
+ tier: 1,
+ outcomes: [
+ { label: 'YES (>50bps)', price: 0.35, percentage: 35 },
+ { label: 'NO (<=50bps)', price: 0.65, percentage: 65 }
+ ],
+ poolLiquidity: 620000,
+ volume24h: 98000,
+ endTime: '2026-09-30',
+ status: 'ACTIVE'
+ }
+];
+
+interface MarketExploreProps {
+ onSelectMarket: (market: MarketItem) => void;
+}
+
+export const MarketExplore: React.FC = ({ onSelectMarket }) => {
+ const [selectedCategory, setSelectedCategory] = useState('All');
+ const [searchQuery, setSearchQuery] = useState('');
+
+ const categories = ['All', 'Crypto', 'Macro', 'Politics', 'Sports', 'Tech'];
+
+ const filteredMarkets = MOCK_FEATURED_MARKETS.filter((m) => {
+ const matchCategory = selectedCategory === 'All' || m.category === selectedCategory;
+ const matchSearch = m.title.toLowerCase().includes(searchQuery.toLowerCase());
+ return matchCategory && matchSearch;
+ });
+
+ return (
+
+ {/* Hero Banner */}
+
+
+
+
+
+ Power LDA 幂律连续流动性引擎
+
+
+ 全球最具流动性的
+
+ 去中心化预测交易市场
+
+
+
+ 零滑点聚合撮合,支持多选项连续拍卖与极速链上结算。抢先参与热门预测,兑现你的认知价值。
+
+
+
+
+ {/* Filter & Search Bar */}
+
+ {/* Category Tabs */}
+
+ {categories.map((cat) => (
+
+ ))}
+
+
+ {/* Search Input */}
+
+
+ setSearchQuery(e.target.value)}
+ placeholder="搜索预测事件 / 资产..."
+ className="w-full bg-slate-900/90 border border-slate-800 rounded-xl pl-9 pr-4 py-2 text-xs text-slate-100 placeholder-slate-500 focus:outline-none focus:border-cyan-500/50"
+ />
+
+
+
+ {/* Market Cards Grid */}
+
+ {filteredMarkets.map((market) => (
+
onSelectMarket(market)}
+ className="group bg-[#0f111d] hover:bg-[#141726] border border-slate-800/80 hover:border-cyan-500/40 rounded-2xl p-5 cursor-pointer transition-all duration-200 hover:shadow-xl hover:shadow-cyan-950/20 flex flex-col justify-between"
+ >
+
+ {/* Category & Status */}
+
+
+ {market.category}
+
+
+
+ {market.endTime} 截止
+
+
+
+ {/* Title */}
+
+ {market.title}
+
+
+ {/* Outcomes Bars */}
+
+ {market.outcomes.map((outcome, idx) => (
+
+
+
+ {outcome.label}
+
+ ${outcome.price.toFixed(2)} ({outcome.percentage}%)
+
+
+
+ ))}
+
+
+
+ {/* Footer / Stats */}
+
+
+ 24H 交易量
+ ${market.volume24h.toLocaleString()}
+
+
+ 流动性深度
+ ${market.poolLiquidity.toLocaleString()}
+
+
+
+
+ ))}
+
+
+ );
+};
diff --git a/apps/web/src/features/portfolio/PortfolioView.tsx b/apps/web/src/features/portfolio/PortfolioView.tsx
new file mode 100644
index 0000000..9a5d457
--- /dev/null
+++ b/apps/web/src/features/portfolio/PortfolioView.tsx
@@ -0,0 +1,171 @@
+import React from 'react';
+import { useWeb3 } from '../../context/Web3Context';
+import { PieChart, Clock, ArrowUpRight, ArrowDownLeft, ShieldCheck, History } from 'lucide-react';
+
+export const PortfolioView: React.FC = () => {
+ const { account, wusdBalance } = useWeb3();
+
+ const MOCK_POSITIONS = [
+ {
+ id: 'pos-1',
+ marketTitle: 'Will Bitcoin break above $120,000 before end of Q4 2026?',
+ outcome: 'YES',
+ shares: 1470.5,
+ avgPrice: 0.68,
+ currentPrice: 0.72,
+ currentValue: 1058.76,
+ pnl: 58.76,
+ pnlPct: 5.88
+ },
+ {
+ id: 'pos-2',
+ marketTitle: 'Ethereum Layer-2 Total TVL to reach $50 Billion in 2026?',
+ outcome: 'YES',
+ shares: 617.28,
+ avgPrice: 0.81,
+ currentPrice: 0.85,
+ currentValue: 524.68,
+ pnl: 24.68,
+ pnlPct: 4.93
+ }
+ ];
+
+ const MOCK_LEDGER_ENTRIES = [
+ {
+ id: 'led-1',
+ type: 'TRADE_BUY',
+ desc: '买入 BTC > $120K (YES 1470.5 份)',
+ amount: -1000.0,
+ fee: 6.0,
+ time: '2026-08-31 16:32:10'
+ },
+ {
+ id: 'led-2',
+ type: 'TRADE_BUY',
+ desc: '买入 ETH L2 TVL > $50B (YES 617.28 份)',
+ amount: -500.0,
+ fee: 3.0,
+ time: '2026-08-31 15:45:00'
+ },
+ {
+ id: 'led-3',
+ type: 'DEPOSIT',
+ desc: '链上充值入账 WUSD',
+ amount: 100000.0,
+ fee: 0.0,
+ time: '2026-08-31 14:10:22'
+ }
+ ];
+
+ return (
+
+ {/* Portfolio Top Overview */}
+
+
+
总持仓市值 (Portfolio Value)
+
$1,583.44 WUSD
+
+ +$83.44 (+5.56%)
+ 未实现盈亏
+
+
+
+
+
可用保证金余额 (Available Balance)
+
+ {Number(wusdBalance).toLocaleString(undefined, { maximumFractionDigits: 2 })} WUSD
+
+
随时可用于下注买入或提现
+
+
+
+
活跃预测头寸 (Active Positions)
+
2 个市场
+
持仓均基于不可变智能合约保护
+
+
+
+ {/* Positions Table */}
+
+
+
+
当前持仓明细 (Active Positions)
+
+
+
+
+
+
+ | 预测市场 |
+ 预测选项 |
+ 持有份额 |
+ 开仓均价 |
+ 当前市价 |
+ 当前估值 |
+ 未实现盈亏 |
+
+
+
+ {MOCK_POSITIONS.map((pos) => (
+
+ | {pos.marketTitle} |
+
+
+ {pos.outcome}
+
+ |
+ {pos.shares.toLocaleString()} |
+ ${pos.avgPrice} |
+ ${pos.currentPrice} |
+ ${pos.currentValue.toFixed(2)} |
+
+ +${pos.pnl.toFixed(2)} (+{pos.pnlPct}%)
+ |
+
+ ))}
+
+
+
+
+
+ {/* Immutable Ledger History Table */}
+
+
+
+
+
不可变复式记账流水 (Immutable Ledger)
+
法定链上/链下资金变动流水,防篡改逐笔审计
+
+
+
+
+ {MOCK_LEDGER_ENTRIES.map((entry) => (
+
+
+
+ {entry.type === 'DEPOSIT' ?
:
}
+
+
+
{entry.desc}
+
{entry.time} • 手续费: ${entry.fee}
+
+
+
+
+ = 0 ? 'text-emerald-400' : 'text-slate-200'}>
+ {entry.amount >= 0 ? `+${entry.amount.toLocaleString()}` : `${entry.amount.toLocaleString()}`} WUSD
+
+
+
+ ))}
+
+
+
+ );
+};
diff --git a/apps/web/src/features/trading/TradingTerminal.tsx b/apps/web/src/features/trading/TradingTerminal.tsx
new file mode 100644
index 0000000..88d0efb
--- /dev/null
+++ b/apps/web/src/features/trading/TradingTerminal.tsx
@@ -0,0 +1,304 @@
+import React, { useState } from 'react';
+import { useWeb3 } from '../../context/Web3Context';
+import { MarketItem } from '../explore/MarketExplore';
+import { ethers } from 'ethers';
+import { TrendingUp, ArrowDownUp, Check, AlertCircle, Loader2, Sparkles, Activity, ShieldCheck } from 'lucide-react';
+
+interface TradingTerminalProps {
+ market: MarketItem;
+}
+
+export const TradingTerminal: React.FC = ({ market }) => {
+ const { account, signer, getCollateralContract, wusdBalance, refreshBalance, isCorrectNetwork } = useWeb3();
+
+ const [selectedOutcomeIndex, setSelectedOutcomeIndex] = useState(0);
+ const [tradeSide, setTradeSide] = useState<'BUY' | 'SELL'>('BUY');
+ const [amount, setAmount] = useState('100');
+ const [loading, setLoading] = useState(false);
+ const [statusMsg, setStatusMsg] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
+
+ const activeOutcome = market.outcomes[selectedOutcomeIndex];
+ const estShares = amount && Number(amount) > 0 ? (Number(amount) / activeOutcome.price).toFixed(2) : '0';
+ const estPayout = (Number(estShares) * 1.0).toFixed(2);
+ const estReturn = amount && Number(amount) > 0 ? (((Number(estPayout) - Number(amount)) / Number(amount)) * 100).toFixed(1) : '0';
+
+ const handleTrade = async (e: React.FormEvent) => {
+ e.preventDefault();
+ if (!signer || !account) {
+ setStatusMsg({ type: 'error', text: '请先连接钱包以进行交易!' });
+ return;
+ }
+ if (!isCorrectNetwork) {
+ setStatusMsg({ type: 'error', text: '请切换至 Robinhood Testnet 网络!' });
+ return;
+ }
+
+ try {
+ setLoading(true);
+ setStatusMsg(null);
+
+ const collateral = getCollateralContract();
+ if (!collateral) throw new Error('Collateral contract not loaded');
+
+ const amountWei = ethers.parseUnits(amount, 18);
+
+ // Step 1: Approve Collateral
+ setStatusMsg({ type: 'success', text: '步骤 1/2: 正在授权扣减 WUSD 保证金...' });
+ const appTx = await collateral.approve(market.marketAddress, ethers.MaxUint256);
+ await appTx.wait();
+
+ // Step 2: In web2-like demo / testnet, complete trade
+ setStatusMsg({ type: 'success', text: `🎉 订单已撮合成交!已以 $${activeOutcome.price} 买入 ${estShares} 份 ${activeOutcome.label} 预测代币。` });
+ refreshBalance();
+ } catch (err: any) {
+ console.error('Trade error:', err);
+ setStatusMsg({ type: 'error', text: err.reason || err.message || '交易失败' });
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+ {/* Left 2 Cols: Market Title, Chart, Curve Status */}
+
+ {/* Header Summary */}
+
+
+
+ {market.category} • Tier {market.tier}
+
+
+ 结算截止: {market.endTime}
+
+
+
+
+ {market.title}
+
+
+
+
+ 24H 交易量
+ ${market.volume24h.toLocaleString()}
+
+
+ 流动性资金池
+ ${market.poolLiquidity.toLocaleString()}
+
+
+ 联合曲线状态
+ Power LDA (活跃)
+
+
+ 协议手续费
+ 0.6%
+
+
+
+
+ {/* High-frequency Chart Simulation */}
+
+
+
+
+
实时胜率走势 & 概率曲线 (Real-Time Price & Probability)
+
+
+ {['1H', '6H', '24H', '7D', 'ALL'].map((tf, i) => (
+
+ ))}
+
+
+
+ {/* SVG Chart Graphic */}
+
+
+
+
+ 00:00
+ 06:00
+ 12:00
+ 18:00
+ LIVE
+
+
+
+
+
+ {/* Right Col: Instant Order Placement Panel */}
+
+
+
+ {/* Status Message */}
+ {statusMsg && (
+
+ {statusMsg.type === 'success' ? (
+
+ ) : (
+
+ )}
+
+
+ )}
+
+
+ );
+};
diff --git a/apps/web/tailwind.config.js b/apps/web/tailwind.config.js
new file mode 100644
index 0000000..3afb208
--- /dev/null
+++ b/apps/web/tailwind.config.js
@@ -0,0 +1,21 @@
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: [
+ './src/**/*.{js,ts,jsx,tsx,mdx}',
+ '../../packages/ui/src/**/*.{js,ts,jsx,tsx,mdx}'
+ ],
+ theme: {
+ extend: {
+ colors: {
+ background: '#090A0F',
+ card: '#12141F',
+ border: '#1F2438',
+ primary: '#3B82F6',
+ success: '#10B981',
+ danger: '#EF4444',
+ warning: '#F59E0B'
+ }
+ }
+ },
+ plugins: []
+};
diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json
new file mode 100644
index 0000000..c541b13
--- /dev/null
+++ b/apps/web/tsconfig.json
@@ -0,0 +1,35 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "lib": [
+ "dom",
+ "dom.iterable",
+ "esnext"
+ ],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": false,
+ "noEmit": true,
+ "incremental": true,
+ "module": "esnext",
+ "esModuleInterop": true,
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "preserve",
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ]
+ },
+ "include": [
+ "next-env.d.ts",
+ ".next/types/**/*.ts",
+ "**/*.ts",
+ "**/*.tsx"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c8ca61b..c130829 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -75,15 +75,24 @@ importers:
'@wtfx/api-client':
specifier: workspace:*
version: link:../../packages/api-client
+ '@wtfx/contracts':
+ specifier: workspace:*
+ version: link:../../packages/contracts
'@wtfx/types':
specifier: workspace:*
version: link:../../packages/types
'@wtfx/ui':
specifier: workspace:*
version: link:../../packages/ui
+ clsx:
+ specifier: ^2.1.1
+ version: 2.1.1
ethers:
specifier: ^6.13.0
version: 6.17.0
+ lucide-react:
+ specifier: ^0.395.0
+ version: 0.395.0(react@18.3.1)
next:
specifier: ^14.2.4
version: 14.2.35(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -93,6 +102,31 @@ importers:
react-dom:
specifier: ^18.3.1
version: 18.3.1(react@18.3.1)
+ tailwind-merge:
+ specifier: ^2.3.0
+ version: 2.6.1
+ devDependencies:
+ '@types/node':
+ specifier: ^20.14.2
+ version: 20.19.43
+ '@types/react':
+ specifier: ^18.3.3
+ version: 18.3.31
+ '@types/react-dom':
+ specifier: ^18.3.0
+ version: 18.3.7(@types/react@18.3.31)
+ autoprefixer:
+ specifier: ^10.4.19
+ version: 10.5.4(postcss@8.5.26)
+ postcss:
+ specifier: ^8.4.38
+ version: 8.5.26
+ tailwindcss:
+ specifier: ^3.4.4
+ version: 3.4.19
+ typescript:
+ specifier: ^5.4.5
+ version: 5.9.3
packages/api-client:
dependencies: