diff --git a/app/profile/page.tsx b/app/profile/page.tsx index 8fe24f1..d78d05f 100644 --- a/app/profile/page.tsx +++ b/app/profile/page.tsx @@ -5,6 +5,7 @@ import { useSession } from 'next-auth/react' import { redirect } from 'next/navigation' import type { UserProfile } from '@/lib/api-schema' import ProfileForm from '@/components/profile/ProfileForm' +import ContractDemo from '@/components/web3/ContractDemo' const fetchProfile = async (): Promise => { const res = await fetch('/api/profile') @@ -13,7 +14,6 @@ const fetchProfile = async (): Promise => { } export default function ProfilePage() { - // Protect the route const { status } = useSession({ required: true, onUnauthenticated() { @@ -36,8 +36,15 @@ export default function ProfilePage() { return (
-

Edit Your Profile

- {profile && } +
+

Edit Your Profile

+ {profile && } +
+ +
+

Web3 Contract Interaction

+ +
) } diff --git a/components/web3/ContractDemo.tsx b/components/web3/ContractDemo.tsx new file mode 100644 index 0000000..f304d50 --- /dev/null +++ b/components/web3/ContractDemo.tsx @@ -0,0 +1,95 @@ +'use client' + +import { proofOfFandomContract } from '@/lib/contracts' +import { + useAccount, + useReadContract, + useWriteContract, + useWaitForTransactionReceipt, +} from 'wagmi' +import { useState } from 'react' + +export default function ContractDemo() { + const { address, isConnected } = useAccount() + const [minted, setMinted] = useState(false) + + const { data: balance, isLoading: isBalanceLoading } = useReadContract({ + ...proofOfFandomContract, + functionName: 'balanceOf', + args: [address!], + query: { + enabled: isConnected, + }, + }) + + const { data: hash, writeContract, isPending } = useWriteContract() + + const { isLoading: isConfirming, isSuccess: isConfirmed } = + useWaitForTransactionReceipt({ + hash, + }) + + const handleMint = () => { + writeContract({ + ...proofOfFandomContract, + functionName: 'mint', + args: [], + }) + } + + if (isConfirmed && !minted) { + setMinted(true) + } + + if (!isConnected) { + return ( +

+ Please connect your wallet to interact with the contract. +

+ ) + } + + return ( +
+

Proof of Fandom Contract

+ +
+

Your Fandom Token Balance:

+ {isBalanceLoading ? ( + Loading... + ) : ( + + {balance?.toString() ?? '0'} + + )} +
+ +
+ + {hash && ( +

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

+ )} + {minted && ( +

Minted Successfully!

+ )} +
+

+ Note: This interacts with a dummy contract address. The transaction will + be sent but is expected to fail on-chain. This demo is to verify the + frontend flow. +

+
+ ) +} diff --git a/lib/abi/ProofOfFandom.json b/lib/abi/ProofOfFandom.json new file mode 100644 index 0000000..9486142 --- /dev/null +++ b/lib/abi/ProofOfFandom.json @@ -0,0 +1,28 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/lib/abi/contracts.ts b/lib/abi/contracts.ts new file mode 100644 index 0000000..47bcfeb --- /dev/null +++ b/lib/abi/contracts.ts @@ -0,0 +1,12 @@ +import proofOfFandomAbi from './abi/ProofOfFandom.json' +import { flare, songbird } from './chains' + +const proofOfFandomAddress = + '0x1234567890123456789012345678901234567890' as const + +export const proofOfFandomContract = { + address: proofOfFandomAddress, + abi: proofOfFandomAbi, + + chains: [flare.id, songbird.id], +}