feat(vault): add user vault factory, non-custodial deposit/withdraw and session key UI
This commit is contained in:
@@ -1,9 +1,51 @@
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { useWeb3 } from '../../context/Web3Context';
|
||||
import { PieChart, Clock, ArrowUpRight, ArrowDownLeft, ShieldCheck, History } from 'lucide-react';
|
||||
import { PieChart, Clock, ArrowUpRight, ArrowDownLeft, ShieldCheck, History, KeyRound, ArrowRightLeft, Loader2, Check } from 'lucide-react';
|
||||
|
||||
export const PortfolioView: React.FC = () => {
|
||||
const { account, wusdBalance } = useWeb3();
|
||||
const { account, wusdBalance, vaultAddress, isSessionActive, depositToVault, withdrawFromVault, enableSessionKey } = useWeb3();
|
||||
const [depositAmount, setDepositAmount] = useState<string>('500');
|
||||
const [withdrawAmount, setWithdrawAmount] = useState<string>('100');
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [actionMsg, setActionMsg] = useState<string | null>(null);
|
||||
|
||||
const handleDeposit = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setActionMsg(null);
|
||||
const hash = await depositToVault(depositAmount);
|
||||
setActionMsg(`🎉 成功存入 ${depositAmount} WUSD 到专属非托管金库!Tx: ${hash.slice(0, 10)}...`);
|
||||
} catch (e: any) {
|
||||
alert(e.message || '充值失败');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleWithdraw = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setActionMsg(null);
|
||||
const hash = await withdrawFromVault(withdrawAmount);
|
||||
setActionMsg(`🎉 成功从金库提现 ${withdrawAmount} WUSD 到钱包!Tx: ${hash.slice(0, 10)}...`);
|
||||
} catch (e: any) {
|
||||
alert(e.message || '提现失败');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleEnableSession = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
await enableSessionKey();
|
||||
setActionMsg('⚡ Session Key 免密连击授权成功!24小时内高频交易零弹窗!');
|
||||
} catch (e: any) {
|
||||
alert(e.message || '授权失败');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const MOCK_POSITIONS = [
|
||||
{
|
||||
@@ -79,12 +121,96 @@ export const PortfolioView: React.FC = () => {
|
||||
</div>
|
||||
|
||||
<div className="bg-[#0f111d] border border-slate-800 rounded-2xl p-6 shadow-xl">
|
||||
<span className="text-xs text-slate-400 block font-medium">活跃预测头寸 (Active Positions)</span>
|
||||
<span className="text-2xl font-black font-mono text-slate-200 mt-1 block">2 个市场</span>
|
||||
<div className="text-xs text-slate-500 mt-2">持仓均基于不可变智能合约保护</div>
|
||||
<span className="text-xs text-slate-400 block font-medium">专属非托管智能金库 (AA User Vault)</span>
|
||||
<span className="text-xs font-mono text-slate-300 truncate block mt-1">
|
||||
{vaultAddress || '连接钱包后自动生成'}
|
||||
</span>
|
||||
<div className="flex items-center space-x-1 text-xs text-emerald-400 font-semibold mt-2">
|
||||
<ShieldCheck className="w-3.5 h-3.5" />
|
||||
<span>100% 资金链上非托管</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Non-Custodial Vault Operations Panel */}
|
||||
<div className="bg-[#0f111d] border border-cyan-900/30 rounded-2xl p-6 shadow-xl space-y-4">
|
||||
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 border-b border-slate-800 pb-4">
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="p-2.5 bg-cyan-500/10 rounded-xl border border-cyan-500/20 text-cyan-400">
|
||||
<KeyRound className="w-5 h-5" />
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="font-bold text-base text-white">非托管智能金库与免密连击管理 (AA Smart Vault)</h2>
|
||||
<p className="text-xs text-slate-400">平台无法转移你的资产,充值后可开启 Session Key 实现毫秒级 0 弹窗高频交易</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={handleEnableSession}
|
||||
disabled={loading || isSessionActive || !account}
|
||||
className={`px-4 py-2 rounded-xl text-xs font-bold transition-all flex items-center space-x-1.5 ${
|
||||
isSessionActive
|
||||
? 'bg-emerald-950/60 text-emerald-400 border border-emerald-800/50 cursor-default'
|
||||
: 'bg-gradient-to-r from-cyan-500 to-indigo-600 hover:from-cyan-400 hover:to-indigo-500 text-white shadow-md shadow-cyan-500/20'
|
||||
}`}
|
||||
>
|
||||
<KeyRound className="w-3.5 h-3.5" />
|
||||
<span>{isSessionActive ? '⚡ 免密 Session 已激活 (24H 有效)' : '开启免密连击交易 (Session Key)'}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 pt-2">
|
||||
{/* Deposit */}
|
||||
<div className="bg-slate-950/60 border border-slate-800 rounded-xl p-4 space-y-3">
|
||||
<span className="text-xs font-bold text-slate-300 block">充值到专属智能金库 (Deposit to Vault)</span>
|
||||
<div className="flex space-x-2">
|
||||
<input
|
||||
type="number"
|
||||
value={depositAmount}
|
||||
onChange={(e) => setDepositAmount(e.target.value)}
|
||||
placeholder="500"
|
||||
className="flex-1 bg-slate-900 border border-slate-700 rounded-lg px-3 py-2 text-xs font-mono text-slate-100 focus:outline-none focus:border-cyan-500"
|
||||
/>
|
||||
<button
|
||||
onClick={handleDeposit}
|
||||
disabled={loading || !account || !depositAmount}
|
||||
className="px-4 py-2 bg-cyan-600 hover:bg-cyan-500 text-white rounded-lg text-xs font-bold transition-colors disabled:opacity-50"
|
||||
>
|
||||
{loading ? <Loader2 className="w-3.5 h-3.5 animate-spin" /> : '立即充值'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Withdraw */}
|
||||
<div className="bg-slate-950/60 border border-slate-800 rounded-xl p-4 space-y-3">
|
||||
<span className="text-xs font-bold text-slate-300 block">随时提现到 EOA 钱包 (Instant Withdraw)</span>
|
||||
<div className="flex space-x-2">
|
||||
<input
|
||||
type="number"
|
||||
value={withdrawAmount}
|
||||
onChange={(e) => setWithdrawAmount(e.target.value)}
|
||||
placeholder="100"
|
||||
className="flex-1 bg-slate-900 border border-slate-700 rounded-lg px-3 py-2 text-xs font-mono text-slate-100 focus:outline-none focus:border-cyan-500"
|
||||
/>
|
||||
<button
|
||||
onClick={handleWithdraw}
|
||||
disabled={loading || !account || !withdrawAmount}
|
||||
className="px-4 py-2 bg-slate-800 hover:bg-slate-700 text-slate-200 border border-slate-600 rounded-lg text-xs font-bold transition-colors disabled:opacity-50"
|
||||
>
|
||||
{loading ? <Loader2 className="w-3.5 h-3.5 animate-spin" /> : '提取本金'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{actionMsg && (
|
||||
<div className="p-3 bg-emerald-950/30 border border-emerald-800/40 rounded-xl text-xs text-emerald-300 flex items-center space-x-2">
|
||||
<Check className="w-4 h-4 text-emerald-400" />
|
||||
<span>{actionMsg}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Positions Table */}
|
||||
<div className="bg-[#0f111d] border border-slate-800 rounded-2xl p-6 shadow-xl space-y-4">
|
||||
<div className="flex items-center space-x-2 border-b border-slate-800/80 pb-4">
|
||||
|
||||
Reference in New Issue
Block a user