feat(vault): add user vault factory, non-custodial deposit/withdraw and session key UI
This commit is contained in:
@@ -9,9 +9,14 @@ interface Web3ContextType {
|
|||||||
chainId: number | null;
|
chainId: number | null;
|
||||||
isCorrectNetwork: boolean;
|
isCorrectNetwork: boolean;
|
||||||
wusdBalance: string;
|
wusdBalance: string;
|
||||||
|
vaultAddress: string | null;
|
||||||
|
isSessionActive: boolean;
|
||||||
connectWallet: () => Promise<void>;
|
connectWallet: () => Promise<void>;
|
||||||
switchNetwork: () => Promise<void>;
|
switchNetwork: () => Promise<void>;
|
||||||
refreshBalance: () => Promise<void>;
|
refreshBalance: () => Promise<void>;
|
||||||
|
depositToVault: (amount: string) => Promise<string>;
|
||||||
|
withdrawFromVault: (amount: string) => Promise<string>;
|
||||||
|
enableSessionKey: () => Promise<void>;
|
||||||
getMarketContract: (address: string) => ethers.Contract | null;
|
getMarketContract: (address: string) => ethers.Contract | null;
|
||||||
getCollateralContract: () => ethers.Contract | null;
|
getCollateralContract: () => ethers.Contract | null;
|
||||||
}
|
}
|
||||||
@@ -23,9 +28,14 @@ const Web3Context = createContext<Web3ContextType>({
|
|||||||
chainId: null,
|
chainId: null,
|
||||||
isCorrectNetwork: false,
|
isCorrectNetwork: false,
|
||||||
wusdBalance: '0',
|
wusdBalance: '0',
|
||||||
|
vaultAddress: null,
|
||||||
|
isSessionActive: false,
|
||||||
connectWallet: async () => {},
|
connectWallet: async () => {},
|
||||||
switchNetwork: async () => {},
|
switchNetwork: async () => {},
|
||||||
refreshBalance: async () => {},
|
refreshBalance: async () => {},
|
||||||
|
depositToVault: async () => '',
|
||||||
|
withdrawFromVault: async () => '',
|
||||||
|
enableSessionKey: async () => {},
|
||||||
getMarketContract: () => null,
|
getMarketContract: () => null,
|
||||||
getCollateralContract: () => null,
|
getCollateralContract: () => null,
|
||||||
});
|
});
|
||||||
@@ -36,9 +46,23 @@ export const Web3Provider: React.FC<{ children: React.ReactNode }> = ({ children
|
|||||||
const [signer, setSigner] = useState<ethers.Signer | null>(null);
|
const [signer, setSigner] = useState<ethers.Signer | null>(null);
|
||||||
const [chainId, setChainId] = useState<number | null>(null);
|
const [chainId, setChainId] = useState<number | null>(null);
|
||||||
const [wusdBalance, setWusdBalance] = useState<string>('0');
|
const [wusdBalance, setWusdBalance] = useState<string>('0');
|
||||||
|
const [vaultAddress, setVaultAddress] = useState<string | null>(null);
|
||||||
|
const [isSessionActive, setIsSessionActive] = useState<boolean>(false);
|
||||||
|
|
||||||
const isCorrectNetwork = chainId === ROBINHOOD_TESTNET_CHAIN.id;
|
const isCorrectNetwork = chainId === ROBINHOOD_TESTNET_CHAIN.id;
|
||||||
|
|
||||||
|
const predictUserVault = async (userAddr: string, prov: ethers.BrowserProvider) => {
|
||||||
|
try {
|
||||||
|
const factoryAddr = DEPLOYMENTS.robinhoodTestnet.contracts.vaultFactory;
|
||||||
|
if (!factoryAddr) return;
|
||||||
|
const factoryContract = new ethers.Contract(factoryAddr, ABIS.WTFVaultFactory, prov);
|
||||||
|
const predicted = await factoryContract.predictVaultAddress(userAddr);
|
||||||
|
setVaultAddress(predicted);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to predict vault address:', e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const refreshBalance = async () => {
|
const refreshBalance = async () => {
|
||||||
if (!account || !provider) return;
|
if (!account || !provider) return;
|
||||||
try {
|
try {
|
||||||
@@ -73,10 +97,13 @@ export const Web3Provider: React.FC<{ children: React.ReactNode }> = ({ children
|
|||||||
(window as any).ethereum.on('accountsChanged', async (accs: string[]) => {
|
(window as any).ethereum.on('accountsChanged', async (accs: string[]) => {
|
||||||
if (accs.length > 0) {
|
if (accs.length > 0) {
|
||||||
setAccount(accs[0]);
|
setAccount(accs[0]);
|
||||||
setSigner(await browserProvider.getSigner());
|
const currentSigner = await browserProvider.getSigner();
|
||||||
|
setSigner(currentSigner);
|
||||||
|
predictUserVault(accs[0], browserProvider);
|
||||||
} else {
|
} else {
|
||||||
setAccount(null);
|
setAccount(null);
|
||||||
setSigner(null);
|
setSigner(null);
|
||||||
|
setVaultAddress(null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -157,6 +184,44 @@ export const Web3Provider: React.FC<{ children: React.ReactNode }> = ({ children
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const depositToVault = async (amountStr: string): Promise<string> => {
|
||||||
|
if (!signer || !account || !vaultAddress) throw new Error('Wallet/Vault not ready');
|
||||||
|
const collateral = new ethers.Contract(
|
||||||
|
DEPLOYMENTS.robinhoodTestnet.contracts.collateral,
|
||||||
|
ABIS.MockERC20,
|
||||||
|
signer
|
||||||
|
);
|
||||||
|
const amountWei = ethers.parseUnits(amountStr, 18);
|
||||||
|
const tx = await collateral.transfer(vaultAddress, amountWei);
|
||||||
|
await tx.wait();
|
||||||
|
refreshBalance();
|
||||||
|
return tx.hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
const withdrawFromVault = async (amountStr: string): Promise<string> => {
|
||||||
|
if (!signer || !account || !vaultAddress) throw new Error('Wallet/Vault not ready');
|
||||||
|
const vault = new ethers.Contract(vaultAddress, ABIS.WTFUserVault, signer);
|
||||||
|
const amountWei = ethers.parseUnits(amountStr, 18);
|
||||||
|
const tx = await vault.withdraw(
|
||||||
|
DEPLOYMENTS.robinhoodTestnet.contracts.collateral,
|
||||||
|
account,
|
||||||
|
amountWei
|
||||||
|
);
|
||||||
|
await tx.wait();
|
||||||
|
refreshBalance();
|
||||||
|
return tx.hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
const enableSessionKey = async () => {
|
||||||
|
if (!signer || !account || !vaultAddress) throw new Error('Wallet/Vault not ready');
|
||||||
|
const vault = new ethers.Contract(vaultAddress, ABIS.WTFUserVault, signer);
|
||||||
|
const relayerAdmin = DEPLOYMENTS.robinhoodTestnet.governance.admin;
|
||||||
|
const duration = 24 * 3600; // 24 hours
|
||||||
|
const tx = await vault.authorizeSession(relayerAdmin, duration);
|
||||||
|
await tx.wait();
|
||||||
|
setIsSessionActive(true);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Web3Context.Provider
|
<Web3Context.Provider
|
||||||
value={{
|
value={{
|
||||||
@@ -166,9 +231,14 @@ export const Web3Provider: React.FC<{ children: React.ReactNode }> = ({ children
|
|||||||
chainId,
|
chainId,
|
||||||
isCorrectNetwork,
|
isCorrectNetwork,
|
||||||
wusdBalance,
|
wusdBalance,
|
||||||
|
vaultAddress,
|
||||||
|
isSessionActive,
|
||||||
connectWallet,
|
connectWallet,
|
||||||
switchNetwork,
|
switchNetwork,
|
||||||
refreshBalance,
|
refreshBalance,
|
||||||
|
depositToVault,
|
||||||
|
withdrawFromVault,
|
||||||
|
enableSessionKey,
|
||||||
getMarketContract,
|
getMarketContract,
|
||||||
getCollateralContract,
|
getCollateralContract,
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,9 +1,51 @@
|
|||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import { useWeb3 } from '../../context/Web3Context';
|
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 = () => {
|
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 = [
|
const MOCK_POSITIONS = [
|
||||||
{
|
{
|
||||||
@@ -79,11 +121,95 @@ export const PortfolioView: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="bg-[#0f111d] border border-slate-800 rounded-2xl p-6 shadow-xl">
|
<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-xs text-slate-400 block font-medium">专属非托管智能金库 (AA User Vault)</span>
|
||||||
<span className="text-2xl font-black font-mono text-slate-200 mt-1 block">2 个市场</span>
|
<span className="text-xs font-mono text-slate-300 truncate block mt-1">
|
||||||
<div className="text-xs text-slate-500 mt-2">持仓均基于不可变智能合约保护</div>
|
{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>
|
</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 */}
|
{/* Positions Table */}
|
||||||
<div className="bg-[#0f111d] border border-slate-800 rounded-2xl p-6 shadow-xl space-y-4">
|
<div className="bg-[#0f111d] border border-slate-800 rounded-2xl p-6 shadow-xl space-y-4">
|
||||||
|
|||||||
@@ -0,0 +1,294 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "_owner",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "constructor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "token",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "from",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "amount",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Deposited",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "target",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "value",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "bytes",
|
||||||
|
"name": "data",
|
||||||
|
"type": "bytes"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Executed",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "sessionKey",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "expiry",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "SessionAuthorized",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "sessionKey",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "SessionRevoked",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "token",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "to",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "amount",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Withdrawn",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "token",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "spender",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "amount",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "approveToken",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "sessionKey",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "duration",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "authorizeSession",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "target",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "value",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "bytes",
|
||||||
|
"name": "data",
|
||||||
|
"type": "bytes"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "execute",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "bytes",
|
||||||
|
"name": "",
|
||||||
|
"type": "bytes"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "payable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "factory",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "isRelayer",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "bool",
|
||||||
|
"name": "",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "owner",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "sessionKey",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "revokeSession",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "sessionExpiry",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "token",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "to",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "amount",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "withdraw",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"stateMutability": "payable",
|
||||||
|
"type": "receive"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "user",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "vault",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "vaultIndex",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "VaultCreated",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "allVaults",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "user",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "getOrCreateVault",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "vault",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "getVault",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "user",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "predictVaultAddress",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -1,12 +1,16 @@
|
|||||||
import WTFControllerV2Abi from './abis/WTFControllerV2.json';
|
import WTFControllerV2Abi from './abis/WTFControllerV2.json';
|
||||||
import MockERC20Abi from './abis/MockERC20.json';
|
import MockERC20Abi from './abis/MockERC20.json';
|
||||||
import WTFMarketV2Abi from './abis/WTFMarketV2.json';
|
import WTFMarketV2Abi from './abis/WTFMarketV2.json';
|
||||||
|
import WTFVaultFactoryAbi from './abis/WTFVaultFactory.json';
|
||||||
|
import WTFUserVaultAbi from './abis/WTFUserVault.json';
|
||||||
import robinhoodTestnetDeployment from './robinhoodTestnet.json';
|
import robinhoodTestnetDeployment from './robinhoodTestnet.json';
|
||||||
|
|
||||||
export const ABIS = {
|
export const ABIS = {
|
||||||
WTFControllerV2: WTFControllerV2Abi,
|
WTFControllerV2: WTFControllerV2Abi,
|
||||||
MockERC20: MockERC20Abi,
|
MockERC20: MockERC20Abi,
|
||||||
WTFMarketV2: WTFMarketV2Abi
|
WTFMarketV2: WTFMarketV2Abi,
|
||||||
|
WTFVaultFactory: WTFVaultFactoryAbi,
|
||||||
|
WTFUserVault: WTFUserVaultAbi
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEPLOYMENTS = {
|
export const DEPLOYMENTS = {
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"collateral": "0xe776e957953EA69b7Eaa9d7d4098aBC076bDD5E7",
|
"collateral": "0xe776e957953EA69b7Eaa9d7d4098aBC076bDD5E7",
|
||||||
"powerLDACurve": "0xF0E189974c413506098AFB6Bc6Bf4C6715fBf7B1",
|
"powerLDACurve": "0xF0E189974c413506098AFB6Bc6Bf4C6715fBf7B1",
|
||||||
"controllerImplementation": "0x2Aeca49669e9E4E6CdCe46A1bc9bf136765A4f75",
|
"controllerImplementation": "0x2Aeca49669e9E4E6CdCe46A1bc9bf136765A4f75",
|
||||||
"controllerProxy": "0xc0E24E152771C588B21AEB654b30B1cBAf381c1a"
|
"controllerProxy": "0xc0E24E152771C588B21AEB654b30B1cBAf381c1a",
|
||||||
|
"vaultFactory": "0x89401e07296267c01017cA150D5Ec8883a78e0B2"
|
||||||
},
|
},
|
||||||
"governance": {
|
"governance": {
|
||||||
"admin": "0x6cddF384792C77219fc25C454Cfe264757842830",
|
"admin": "0x6cddF384792C77219fc25C454Cfe264757842830",
|
||||||
|
|||||||
Reference in New Issue
Block a user