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;
|
||||
isCorrectNetwork: boolean;
|
||||
wusdBalance: string;
|
||||
vaultAddress: string | null;
|
||||
isSessionActive: boolean;
|
||||
connectWallet: () => Promise<void>;
|
||||
switchNetwork: () => Promise<void>;
|
||||
refreshBalance: () => Promise<void>;
|
||||
depositToVault: (amount: string) => Promise<string>;
|
||||
withdrawFromVault: (amount: string) => Promise<string>;
|
||||
enableSessionKey: () => Promise<void>;
|
||||
getMarketContract: (address: string) => ethers.Contract | null;
|
||||
getCollateralContract: () => ethers.Contract | null;
|
||||
}
|
||||
@@ -23,9 +28,14 @@ const Web3Context = createContext<Web3ContextType>({
|
||||
chainId: null,
|
||||
isCorrectNetwork: false,
|
||||
wusdBalance: '0',
|
||||
vaultAddress: null,
|
||||
isSessionActive: false,
|
||||
connectWallet: async () => {},
|
||||
switchNetwork: async () => {},
|
||||
refreshBalance: async () => {},
|
||||
depositToVault: async () => '',
|
||||
withdrawFromVault: async () => '',
|
||||
enableSessionKey: async () => {},
|
||||
getMarketContract: () => 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 [chainId, setChainId] = useState<number | null>(null);
|
||||
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 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 () => {
|
||||
if (!account || !provider) return;
|
||||
try {
|
||||
@@ -73,10 +97,13 @@ export const Web3Provider: React.FC<{ children: React.ReactNode }> = ({ children
|
||||
(window as any).ethereum.on('accountsChanged', async (accs: string[]) => {
|
||||
if (accs.length > 0) {
|
||||
setAccount(accs[0]);
|
||||
setSigner(await browserProvider.getSigner());
|
||||
const currentSigner = await browserProvider.getSigner();
|
||||
setSigner(currentSigner);
|
||||
predictUserVault(accs[0], browserProvider);
|
||||
} else {
|
||||
setAccount(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 (
|
||||
<Web3Context.Provider
|
||||
value={{
|
||||
@@ -166,9 +231,14 @@ export const Web3Provider: React.FC<{ children: React.ReactNode }> = ({ children
|
||||
chainId,
|
||||
isCorrectNetwork,
|
||||
wusdBalance,
|
||||
vaultAddress,
|
||||
isSessionActive,
|
||||
connectWallet,
|
||||
switchNetwork,
|
||||
refreshBalance,
|
||||
depositToVault,
|
||||
withdrawFromVault,
|
||||
enableSessionKey,
|
||||
getMarketContract,
|
||||
getCollateralContract,
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user