@@ -134,10 +200,6 @@ export function WUSDPanel() {
{isPending ? t('wusd.confirming') : isConfirming ? t('wusd.minting') : t('wusd.mint')}
- {isSuccess && (
-
{t('wusd.mintSuccess')}
- )}
-
{/* 边界测试区域 */}
setShowBoundaryTest(!showBoundaryTest)} style={{ cursor: 'pointer' }}>
@@ -180,6 +242,9 @@ export function WUSDPanel() {
>
)}
+
+ {/* 交易历史 */}
+
)
}
diff --git a/frontend/src/context/TransactionContext.tsx b/frontend/src/context/TransactionContext.tsx
new file mode 100644
index 0000000..052b04d
--- /dev/null
+++ b/frontend/src/context/TransactionContext.tsx
@@ -0,0 +1,33 @@
+import { createContext, useContext } from 'react'
+import type { ReactNode } from 'react'
+import { useTransactionHistory } from '../hooks/useTransactionHistory'
+import type { TransactionRecord, TransactionType } from '../hooks/useTransactionHistory'
+
+interface TransactionContextType {
+ transactions: TransactionRecord[]
+ addTransaction: (tx: Omit
) => string
+ updateTransaction: (id: string, updates: Partial) => void
+ clearHistory: () => void
+}
+
+const TransactionContext = createContext(null)
+
+export function TransactionProvider({ children }: { children: ReactNode }) {
+ const history = useTransactionHistory()
+
+ return (
+
+ {children}
+
+ )
+}
+
+export function useTransactions() {
+ const context = useContext(TransactionContext)
+ if (!context) {
+ throw new Error('useTransactions must be used within TransactionProvider')
+ }
+ return context
+}
+
+export type { TransactionType, TransactionRecord }
diff --git a/frontend/src/hooks/useTransactionHistory.ts b/frontend/src/hooks/useTransactionHistory.ts
new file mode 100644
index 0000000..6a2ed33
--- /dev/null
+++ b/frontend/src/hooks/useTransactionHistory.ts
@@ -0,0 +1,82 @@
+import { useState, useEffect } from 'react'
+
+export type TransactionType = 'mint' | 'burn' | 'buy' | 'sell' | 'approve' | 'create_vault' | 'update_price' | 'test'
+
+export interface TransactionRecord {
+ id: string
+ type: TransactionType
+ hash: string
+ timestamp: number
+ status: 'pending' | 'success' | 'failed'
+ amount?: string
+ token?: string
+ vault?: string
+ error?: string
+}
+
+const STORAGE_KEY = 'yt_asset_tx_history'
+const MAX_RECORDS = 50
+
+export function useTransactionHistory() {
+ const [transactions, setTransactions] = useState([])
+
+ // 从 localStorage 加载历史记录
+ useEffect(() => {
+ try {
+ const stored = localStorage.getItem(STORAGE_KEY)
+ if (stored) {
+ setTransactions(JSON.parse(stored))
+ }
+ } catch (e) {
+ console.error('Failed to load transaction history:', e)
+ }
+ }, [])
+
+ // 保存到 localStorage
+ const saveToStorage = (records: TransactionRecord[]) => {
+ try {
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(records.slice(0, MAX_RECORDS)))
+ } catch (e) {
+ console.error('Failed to save transaction history:', e)
+ }
+ }
+
+ // 添加新交易
+ const addTransaction = (tx: Omit) => {
+ const newTx: TransactionRecord = {
+ ...tx,
+ id: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
+ timestamp: Date.now(),
+ }
+ setTransactions(prev => {
+ const updated = [newTx, ...prev].slice(0, MAX_RECORDS)
+ saveToStorage(updated)
+ return updated
+ })
+ return newTx.id
+ }
+
+ // 更新交易状态
+ const updateTransaction = (id: string, updates: Partial) => {
+ setTransactions(prev => {
+ const updated = prev.map(tx =>
+ tx.id === id ? { ...tx, ...updates } : tx
+ )
+ saveToStorage(updated)
+ return updated
+ })
+ }
+
+ // 清空历史记录
+ const clearHistory = () => {
+ setTransactions([])
+ localStorage.removeItem(STORAGE_KEY)
+ }
+
+ return {
+ transactions,
+ addTransaction,
+ updateTransaction,
+ clearHistory,
+ }
+}
diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json
index 3f05e8f..134d6ae 100644
--- a/frontend/src/i18n/locales/en.json
+++ b/frontend/src/i18n/locales/en.json
@@ -88,6 +88,22 @@
"en": "English",
"zh": "Chinese"
},
+ "history": {
+ "title": "Transaction History",
+ "empty": "No transactions yet",
+ "clear": "Clear",
+ "viewMore": "View More"
+ },
+ "toast": {
+ "txSubmitted": "Transaction submitted",
+ "txSuccess": "Transaction successful",
+ "txFailed": "Transaction failed",
+ "copySuccess": "Copied to clipboard",
+ "walletError": "Wallet error",
+ "networkError": "Network error",
+ "insufficientBalance": "Insufficient balance",
+ "userRejected": "User rejected the transaction"
+ },
"test": {
"title": "Boundary Test",
"currentStatus": "Current Status",
diff --git a/frontend/src/i18n/locales/zh.json b/frontend/src/i18n/locales/zh.json
index dea7637..888c4d7 100644
--- a/frontend/src/i18n/locales/zh.json
+++ b/frontend/src/i18n/locales/zh.json
@@ -88,6 +88,22 @@
"en": "英文",
"zh": "中文"
},
+ "history": {
+ "title": "交易记录",
+ "empty": "暂无交易记录",
+ "clear": "清空",
+ "viewMore": "查看更多"
+ },
+ "toast": {
+ "txSubmitted": "交易已提交",
+ "txSuccess": "交易成功",
+ "txFailed": "交易失败",
+ "copySuccess": "已复制到剪贴板",
+ "walletError": "钱包错误",
+ "networkError": "网络错误",
+ "insufficientBalance": "余额不足",
+ "userRejected": "用户取消了交易"
+ },
"test": {
"title": "边界测试",
"currentStatus": "当前状态",
diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts
index 807024a..3f0fa5a 100644
--- a/frontend/vite.config.ts
+++ b/frontend/vite.config.ts
@@ -9,5 +9,26 @@ export default defineConfig({
host: '0.0.0.0',
strictPort: true,
allowedHosts: ['maxfight.vip', 'localhost', '127.0.0.1'],
- }
+ },
+ build: {
+ rollupOptions: {
+ output: {
+ manualChunks: {
+ // React 相关
+ 'react-vendor': ['react', 'react-dom'],
+ // Web3 相关
+ 'web3-vendor': ['wagmi', 'viem', '@tanstack/react-query'],
+ // WalletConnect 相关
+ 'walletconnect': [
+ '@web3modal/wagmi',
+ '@walletconnect/ethereum-provider',
+ ],
+ // i18n
+ 'i18n': ['react-i18next', 'i18next', 'i18next-browser-languagedetector'],
+ },
+ },
+ },
+ // 提高 chunk 大小警告阈值
+ chunkSizeWarningLimit: 600,
+ },
})