From 65ceeaa91f1e12007415d2a7865aa8caf584a87c Mon Sep 17 00:00:00 2001 From: Sarthak Dengre <134192334+DengreSarthak@users.noreply.github.com> Date: Sun, 1 Jun 2025 00:36:17 +0530 Subject: [PATCH 1/3] Improved writing and reading from the contract. Fixed Ui issues --- web/src/app/[cat]/InteractionClient.tsx | 126 ++++++++++++++++++------ web/src/app/create/page.tsx | 55 +++++++---- web/src/app/my-cats/page.tsx | 24 ++++- web/src/app/page.tsx | 126 +++++++++++++++++------- 4 files changed, 245 insertions(+), 86 deletions(-) diff --git a/web/src/app/[cat]/InteractionClient.tsx b/web/src/app/[cat]/InteractionClient.tsx index 44fe05f5..59515c27 100644 --- a/web/src/app/[cat]/InteractionClient.tsx +++ b/web/src/app/[cat]/InteractionClient.tsx @@ -12,6 +12,7 @@ import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { useAccount, useWriteContract, useWaitForTransactionReceipt } from "wagmi"; import { parseEther } from "viem"; +import { showTransactionToast } from "@/components/ui/transaction-toast"; // Define supported chain IDs type SupportedChainId = 1 | 137 | 534351 | 5115 | 61 | 2001; @@ -35,6 +36,8 @@ export default function InteractionClient() { const [newMaxSupply, setNewMaxSupply] = useState(""); const [newThresholdSupply, setNewThresholdSupply] = useState(""); const [newMaxExpansionRate, setNewMaxExpansionRate] = useState(""); + const [transferRestricted, setTransferRestricted] = useState(true); + const [tokenAddress, setTokenAddress] = useState<`0x${string}`>("0x0"); const [chainId, setChainId] = useState(null); @@ -126,6 +129,14 @@ export default function InteractionClient() { transactionHash: tokenAddress, timestamp: new Date().toISOString(), }); + + const restricted = (await publicClient.readContract({ + address: tokenAddress, + abi: CONTRIBUTION_ACCOUNTING_TOKEN_ABI, + functionName: "transferRestricted", + })) as boolean; + setTransferRestricted(restricted); + } catch (error) { console.error("Error fetching token details:", error); setError("Failed to fetch token details"); @@ -142,13 +153,9 @@ export default function InteractionClient() { // Contract write hooks const { writeContract: mint, data: mintData } = useWriteContract(); - const { writeContract: reduceMaxSupply, data: reduceMaxSupplyData } = useWriteContract(); - const { writeContract: reduceThresholdSupply, data: reduceThresholdSupplyData } = useWriteContract(); - const { writeContract: reduceMaxExpansionRate, data: reduceMaxExpansionRateData } = useWriteContract(); - const { writeContract: disableTransferRestriction, data: disableTransferRestrictionData } = useWriteContract(); // Transaction hooks @@ -172,6 +179,56 @@ export default function InteractionClient() { hash: disableTransferRestrictionData, }); + useEffect(() => { + if (mintData) { + showTransactionToast({ + hash: mintData, + chainId: chainId!, + message: "Tokens minted successfully!", + }); + } + }, [mintData, chainId]); + + useEffect(() => { + if (reduceMaxSupplyData) { + showTransactionToast({ + hash: reduceMaxSupplyData, + chainId: chainId!, + message: "Max supply updated successfully!", + }); + } + }, [reduceMaxSupplyData, chainId]); + + useEffect(() => { + if (reduceThresholdSupplyData) { + showTransactionToast({ + hash: reduceThresholdSupplyData, + chainId: chainId!, + message: "Threshold supply updated successfully!", + }); + } + }, [reduceThresholdSupplyData, chainId]); + + useEffect(() => { + if (reduceMaxExpansionRateData) { + showTransactionToast({ + hash: reduceMaxExpansionRateData, + chainId: chainId!, + message: "Max expansion rate updated successfully!", + }); + } + }, [reduceMaxExpansionRateData, chainId]); + + useEffect(() => { + if (disableTransferRestrictionData) { + showTransactionToast({ + hash: disableTransferRestrictionData, + chainId: chainId!, + message: "Transfer restriction disabled successfully!", + }); + } + }, [disableTransferRestrictionData, chainId]); + if (isLoading) { return (
@@ -195,7 +252,7 @@ export default function InteractionClient() {
{/* Header Section */}
-

+

{tokenDetails.tokenSymbol} Token Management

@@ -261,7 +318,7 @@ export default function InteractionClient() {
- +
- +
- +
- +
-
- - -
+ {transferRestricted ? ( +
+ + +
+ ) : ( +
+ +

Transfer restriction is already disabled

+
+ )}
diff --git a/web/src/app/create/page.tsx b/web/src/app/create/page.tsx index 035535fc..b959f512 100644 --- a/web/src/app/create/page.tsx +++ b/web/src/app/create/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState } from "react"; +import { useState, useEffect } from "react"; import Layout from "@/components/Layout"; import { Button } from "@/components/ui/button"; import { Label } from "@/components/ui/label"; @@ -11,7 +11,7 @@ import { useRouter } from "next/navigation"; import { ClowderVaultFactories } from "@/utils/address"; import { useAccount } from "wagmi"; import { config } from "@/utils/config"; -import { writeContract } from "@wagmi/core"; +import { useWriteContract, useWaitForTransactionReceipt } from "wagmi"; import { CAT_FACTORY_ABI } from "@/contractsABI/CatFactoryABI"; import { Card, @@ -22,6 +22,8 @@ import { } from "@/components/ui/card"; import { Info, Loader2 } from "lucide-react"; import { motion } from "framer-motion"; +import { showTransactionToast } from "@/components/ui/transaction-toast"; + interface DeployContractProps { tokenName: string; tokenSymbol: string; @@ -67,6 +69,7 @@ const fields = [ description: "Maximum percentage the supply can expand (1-100)", }, ]; + export default function CreateCAT() { const [formData, setFormData] = useState({ tokenName: "", @@ -80,6 +83,11 @@ export default function CreateCAT() { const { address, chainId } = useAccount(); const router = useRouter(); + const { writeContract: deployCAT, data: deployData } = useWriteContract(); + const { isLoading: isDeployingTx } = useWaitForTransactionReceipt({ + hash: deployData, + }); + const getTransactionHistory = () => { const history = localStorage.getItem("transactionHistory"); return history ? JSON.parse(history) : []; @@ -112,7 +120,7 @@ export default function CreateCAT() { const formattedThresholdSupply = BigInt(thresholdSupply) * BigInt(1e18); const formattedMaxExpansionRate = BigInt(maxExpansionRate) * BigInt(100); - const tx = await writeContract(config, { + deployCAT({ address: ClowderVaultFactories[chainId], abi: CAT_FACTORY_ABI, functionName: "createCAT", @@ -124,27 +132,40 @@ export default function CreateCAT() { tokenSymbol, ], }); + } catch (error) { + console.error("Error deploying CAT:", error); + showTransactionToast({ + hash: "0x0" as `0x${string}`, + chainId: config.state.chainId, + success: false, + message: "Failed to deploy CAT contract", + }); + setIsDeploying(false); + } + }; + useEffect(() => { + if (deployData) { const txDetails = { - tokenName, - tokenSymbol, - maxSupply, - thresholdSupply, - maxExpansionRate, - transactionHash: tx, + tokenName: formData.tokenName, + tokenSymbol: formData.tokenSymbol, + maxSupply: formData.maxSupply, + thresholdSupply: formData.thresholdSupply, + maxExpansionRate: formData.maxExpansionRate, + transactionHash: deployData, timestamp: new Date().toISOString(), }; saveTransaction(txDetails); - toast.success("CAT contract deployed successfully!"); + showTransactionToast({ + hash: deployData, + chainId: config.state.chainId, + message: "CAT contract deployed successfully!", + }); router.push("/my-cats"); - } catch (error) { - console.error("Error deploying CAT:", error); - toast.error("Failed to deploy CAT contract"); - } finally { setIsDeploying(false); } - }; + }, [deployData, formData, router]); const handleChange = (e: React.ChangeEvent) => { setFormData({ @@ -251,9 +272,9 @@ export default function CreateCAT() { +
From 448ecdfc16eb967b261c689679dc9508f60b69b2 Mon Sep 17 00:00:00 2001 From: Sarthak Dengre <134192334+DengreSarthak@users.noreply.github.com> Date: Sun, 1 Jun 2025 00:36:40 +0530 Subject: [PATCH 2/3] Additional files --- web/src/components/ui/transaction-toast.tsx | 64 +++++++++++++++++++++ web/src/utils/explorer.ts | 17 ++++++ 2 files changed, 81 insertions(+) create mode 100644 web/src/components/ui/transaction-toast.tsx create mode 100644 web/src/utils/explorer.ts diff --git a/web/src/components/ui/transaction-toast.tsx b/web/src/components/ui/transaction-toast.tsx new file mode 100644 index 00000000..8eceffc0 --- /dev/null +++ b/web/src/components/ui/transaction-toast.tsx @@ -0,0 +1,64 @@ +import { CheckCircle2, XCircle, ExternalLink } from "lucide-react"; +import { toast } from "react-hot-toast"; +import { getExplorerUrl } from "@/utils/explorer"; + +interface TransactionToastProps { + hash: `0x${string}`; + chainId: number; + success?: boolean; + message?: string; +} + +export const showTransactionToast = ({ + hash, + chainId, + success = true, + message = success ? "Transaction successful!" : "Transaction failed!", +}: TransactionToastProps) => { + const explorerUrl = getExplorerUrl(hash, chainId); + + toast.custom( + (t) => ( +
+
+
+
+ {success ? ( + + ) : ( + + )} +
+
+

+ {message} +

+

+ Transaction Hash: {hash.slice(0, 6)}...{hash.slice(-4)} +

+
+
+
+ +
+ ), + { + duration: 5000, + position: "bottom-right", + } + ); +}; \ No newline at end of file diff --git a/web/src/utils/explorer.ts b/web/src/utils/explorer.ts new file mode 100644 index 00000000..11438618 --- /dev/null +++ b/web/src/utils/explorer.ts @@ -0,0 +1,17 @@ +export const getExplorerUrl = (hash: `0x${string}`, chainId: number): string => { + const baseUrls: { [key: number]: string } = { + 1: "https://etherscan.io/tx/", + 137: "https://polygonscan.com/tx/", + 534351: "https://sepolia.scrollscan.com/tx/", + 5115: "https://explorer.testnet.mantle.xyz/tx/", + 61: "https://explorer.testnet.rsk.co/tx/", + 2001: "https://explorer.testnet.milkomeda.com/tx/", + }; + + const baseUrl = baseUrls[chainId]; + if (!baseUrl) { + throw new Error(`Unsupported chain ID: ${chainId}`); + } + + return `${baseUrl}${hash}`; +}; \ No newline at end of file From f5e09d9475f57c5da47ca0ae4a760980ae5bc5b8 Mon Sep 17 00:00:00 2001 From: Sarthak Dengre <134192334+DengreSarthak@users.noreply.github.com> Date: Sun, 1 Jun 2025 01:31:36 +0530 Subject: [PATCH 3/3] Modal color fixes --- web/src/app/page.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/web/src/app/page.tsx b/web/src/app/page.tsx index a04ab69a..5a92b2c6 100644 --- a/web/src/app/page.tsx +++ b/web/src/app/page.tsx @@ -269,7 +269,7 @@ export default function Home() { {/* Use CAT Dialog */} - + Use Existing CAT @@ -289,7 +289,7 @@ export default function Home() { value={catAddress} onChange={(e) => setCatAddress(e.target.value)} placeholder="0x..." - className="w-full h-12 text-lg font-mono bg-gray-50 dark:bg-gray-800 border-2 border-gray-200 dark:border-gray-700 dark:text-gray-300 focus:ring-2 focus:ring-blue-500" + className="w-full h-12 text-lg font-mono bg-gray-50 dark:bg-gray-800 border-2 border-gray-200 dark:border-gray-700 dark:text-gray-300 focus:ring-2 focus:ring-blue-500 rounded-xl" />
@@ -297,15 +297,15 @@ export default function Home() { Network