133 lines
4.1 KiB
TypeScript
133 lines
4.1 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { useAccount, useBalance, useWriteContract } from "wagmi";
|
|
import { parseEther, isAddress } from "viem";
|
|
import { WalletConnect } from "@/components/web3/WalletConnect";
|
|
import { TREASURY_WALLET_ABI, CONTRACT_ADDRESSES } from "@/lib/web3/contracts";
|
|
|
|
export default function SendPage() {
|
|
const { address, isConnected } = useAccount();
|
|
const { data: balance } = useBalance({ address });
|
|
const { writeContract } = useWriteContract();
|
|
|
|
const [recipient, setRecipient] = useState("");
|
|
const [amount, setAmount] = useState("");
|
|
const [memo, setMemo] = useState("");
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState("");
|
|
|
|
if (!isConnected) {
|
|
return (
|
|
<div className="min-h-screen p-8">
|
|
<div className="max-w-2xl mx-auto">
|
|
<WalletConnect />
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const handleSend = async () => {
|
|
setError("");
|
|
setLoading(true);
|
|
|
|
try {
|
|
if (!isAddress(recipient)) {
|
|
throw new Error("Invalid recipient address");
|
|
}
|
|
|
|
if (!amount || parseFloat(amount) <= 0) {
|
|
throw new Error("Invalid amount");
|
|
}
|
|
|
|
if (!CONTRACT_ADDRESSES.TreasuryWallet) {
|
|
throw new Error("Treasury wallet not configured");
|
|
}
|
|
|
|
const value = parseEther(amount);
|
|
|
|
// Propose transaction on treasury wallet
|
|
await writeContract({
|
|
address: CONTRACT_ADDRESSES.TreasuryWallet as `0x${string}`,
|
|
abi: TREASURY_WALLET_ABI,
|
|
functionName: "proposeTransaction",
|
|
args: [recipient as `0x${string}`, value, "0x"],
|
|
});
|
|
} catch (err: unknown) {
|
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
setError(error.message || "Transaction failed");
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="min-h-screen p-8">
|
|
<div className="max-w-2xl mx-auto">
|
|
<header className="flex justify-between items-center mb-8">
|
|
<h1 className="text-3xl font-bold">Send Payment</h1>
|
|
<WalletConnect />
|
|
</header>
|
|
|
|
<div className="bg-gray-900 rounded-xl p-8 space-y-6">
|
|
<div>
|
|
<label className="block text-sm font-medium mb-2">Recipient Address</label>
|
|
<input
|
|
type="text"
|
|
value={recipient}
|
|
onChange={(e) => setRecipient(e.target.value)}
|
|
placeholder="0x..."
|
|
className="w-full bg-gray-800 rounded-lg p-3 font-mono text-sm"
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<label className="block text-sm font-medium mb-2">
|
|
Amount ({balance?.symbol || "ETH"})
|
|
</label>
|
|
<input
|
|
type="number"
|
|
step="any"
|
|
value={amount}
|
|
onChange={(e) => setAmount(e.target.value)}
|
|
placeholder="0.0"
|
|
className="w-full bg-gray-800 rounded-lg p-3"
|
|
/>
|
|
{balance && (
|
|
<p className="text-sm text-gray-400 mt-1">
|
|
Available: {balance.formatted} {balance.symbol}
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
<div>
|
|
<label className="block text-sm font-medium mb-2">Memo (Optional)</label>
|
|
<input
|
|
type="text"
|
|
value={memo}
|
|
onChange={(e) => setMemo(e.target.value)}
|
|
placeholder="Payment reference..."
|
|
className="w-full bg-gray-800 rounded-lg p-3"
|
|
/>
|
|
</div>
|
|
|
|
{error && (
|
|
<div className="bg-red-900/20 border border-red-600 rounded-lg p-4">
|
|
<p className="text-red-400">{error}</p>
|
|
</div>
|
|
)}
|
|
|
|
<button
|
|
onClick={handleSend}
|
|
disabled={loading || !recipient || !amount}
|
|
className="w-full px-6 py-3 bg-blue-600 hover:bg-blue-700 disabled:bg-gray-700 disabled:cursor-not-allowed rounded-lg transition-colors font-semibold"
|
|
>
|
|
{loading ? "Processing..." : "Send Payment"}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|