194 lines
6.8 KiB
TypeScript
194 lines
6.8 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { useAccount, useWriteContract, useReadContract } from "wagmi";
|
|
import { WalletConnect } from "@/components/web3/WalletConnect";
|
|
import { TREASURY_WALLET_ABI, CONTRACT_ADDRESSES } from "@/lib/web3/contracts";
|
|
import { formatAddress, isAddress } from "@/lib/utils";
|
|
import { getAddress } from "viem";
|
|
|
|
export default function SettingsPage() {
|
|
const { isConnected } = useAccount();
|
|
const { writeContract } = useWriteContract();
|
|
const [newSigner, setNewSigner] = useState("");
|
|
const [signerToRemove, setSignerToRemove] = useState("");
|
|
const [newThreshold, setNewThreshold] = useState("");
|
|
|
|
// TODO: Fetch owners and threshold from contract
|
|
const { data: owners } = useReadContract({
|
|
address: CONTRACT_ADDRESSES.TreasuryWallet as `0x${string}`,
|
|
abi: TREASURY_WALLET_ABI,
|
|
functionName: "getOwners",
|
|
});
|
|
|
|
const { data: threshold } = useReadContract({
|
|
address: CONTRACT_ADDRESSES.TreasuryWallet as `0x${string}`,
|
|
abi: TREASURY_WALLET_ABI,
|
|
functionName: "threshold",
|
|
});
|
|
|
|
if (!isConnected) {
|
|
return (
|
|
<div className="min-h-screen p-8">
|
|
<div className="max-w-4xl mx-auto">
|
|
<WalletConnect />
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const handleAddSigner = async () => {
|
|
if (!isAddress(newSigner) || !CONTRACT_ADDRESSES.TreasuryWallet) return;
|
|
|
|
await writeContract({
|
|
address: CONTRACT_ADDRESSES.TreasuryWallet as `0x${string}`,
|
|
abi: TREASURY_WALLET_ABI,
|
|
functionName: "addOwner",
|
|
args: [getAddress(newSigner)],
|
|
});
|
|
|
|
setNewSigner("");
|
|
};
|
|
|
|
const handleRemoveSigner = async () => {
|
|
if (!isAddress(signerToRemove) || !CONTRACT_ADDRESSES.TreasuryWallet) return;
|
|
|
|
await writeContract({
|
|
address: CONTRACT_ADDRESSES.TreasuryWallet as `0x${string}`,
|
|
abi: TREASURY_WALLET_ABI,
|
|
functionName: "removeOwner",
|
|
args: [getAddress(signerToRemove)],
|
|
});
|
|
|
|
setSignerToRemove("");
|
|
};
|
|
|
|
const handleChangeThreshold = async () => {
|
|
const thresholdNum = parseInt(newThreshold);
|
|
if (isNaN(thresholdNum) || !CONTRACT_ADDRESSES.TreasuryWallet) return;
|
|
|
|
await writeContract({
|
|
address: CONTRACT_ADDRESSES.TreasuryWallet as `0x${string}`,
|
|
abi: TREASURY_WALLET_ABI,
|
|
functionName: "changeThreshold",
|
|
args: [BigInt(thresholdNum)],
|
|
});
|
|
|
|
setNewThreshold("");
|
|
};
|
|
|
|
return (
|
|
<div className="min-h-screen p-8">
|
|
<div className="max-w-4xl mx-auto">
|
|
<header className="flex justify-between items-center mb-8">
|
|
<h1 className="text-3xl font-bold">Treasury Settings</h1>
|
|
<WalletConnect />
|
|
</header>
|
|
|
|
<div className="space-y-6">
|
|
{/* Current Configuration */}
|
|
<div className="bg-gray-900 rounded-xl p-8">
|
|
<h2 className="text-2xl font-semibold mb-4">Current Configuration</h2>
|
|
<div className="space-y-4">
|
|
<div>
|
|
<label className="block text-sm font-medium mb-2">Threshold</label>
|
|
<div className="text-lg">
|
|
{threshold?.toString()} of {owners?.length || 0} signers required
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium mb-2">Signers</label>
|
|
<div className="space-y-2">
|
|
{owners?.map((owner, index) => (
|
|
<div
|
|
key={owner}
|
|
className="bg-gray-800 rounded-lg p-3 flex justify-between items-center"
|
|
>
|
|
<span className="font-mono text-sm">{formatAddress(owner)}</span>
|
|
{index === 0 && (
|
|
<span className="text-xs text-gray-400">(Deployer)</span>
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Add Signer */}
|
|
<div className="bg-gray-900 rounded-xl p-8">
|
|
<h2 className="text-2xl font-semibold mb-4">Add Signer</h2>
|
|
<div className="flex gap-4">
|
|
<input
|
|
type="text"
|
|
value={newSigner}
|
|
onChange={(e) => setNewSigner(e.target.value)}
|
|
placeholder="0x..."
|
|
className="flex-1 bg-gray-800 rounded-lg p-3 font-mono text-sm"
|
|
/>
|
|
<button
|
|
onClick={handleAddSigner}
|
|
disabled={!isAddress(newSigner)}
|
|
className="px-6 py-3 bg-green-600 hover:bg-green-700 disabled:bg-gray-700 disabled:cursor-not-allowed rounded-lg transition-colors"
|
|
>
|
|
Add
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Remove Signer */}
|
|
<div className="bg-gray-900 rounded-xl p-8">
|
|
<h2 className="text-2xl font-semibold mb-4">Remove Signer</h2>
|
|
<div className="bg-yellow-900/20 border border-yellow-600 rounded-lg p-4 mb-4">
|
|
<p className="text-sm text-yellow-300">
|
|
Warning: Removing a signer requires maintaining threshold validity. You
|
|
cannot remove a signer if it would break the current threshold.
|
|
</p>
|
|
</div>
|
|
<div className="flex gap-4">
|
|
<input
|
|
type="text"
|
|
value={signerToRemove}
|
|
onChange={(e) => setSignerToRemove(e.target.value)}
|
|
placeholder="0x..."
|
|
className="flex-1 bg-gray-800 rounded-lg p-3 font-mono text-sm"
|
|
/>
|
|
<button
|
|
onClick={handleRemoveSigner}
|
|
disabled={!isAddress(signerToRemove)}
|
|
className="px-6 py-3 bg-red-600 hover:bg-red-700 disabled:bg-gray-700 disabled:cursor-not-allowed rounded-lg transition-colors"
|
|
>
|
|
Remove
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Change Threshold */}
|
|
<div className="bg-gray-900 rounded-xl p-8">
|
|
<h2 className="text-2xl font-semibold mb-4">Change Threshold</h2>
|
|
<div className="flex gap-4">
|
|
<input
|
|
type="number"
|
|
value={newThreshold}
|
|
onChange={(e) => setNewThreshold(e.target.value)}
|
|
placeholder={`Current: ${threshold?.toString()}`}
|
|
min="1"
|
|
max={owners?.length || 1}
|
|
className="flex-1 bg-gray-800 rounded-lg p-3"
|
|
/>
|
|
<button
|
|
onClick={handleChangeThreshold}
|
|
disabled={!newThreshold}
|
|
className="px-6 py-3 bg-blue-600 hover:bg-blue-700 disabled:bg-gray-700 disabled:cursor-not-allowed rounded-lg transition-colors"
|
|
>
|
|
Update
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|