|
1 | 1 | import { useMemo } from "react"; |
2 | | -import { useWriteContract, useWaitForTransactionReceipt } from "wagmi"; |
| 2 | +import { useWriteContract, useWaitForTransactionReceipt, useAccount, useConfig } from "wagmi"; |
| 3 | +import { simulateContract, readContract } from "@wagmi/core"; |
3 | 4 | import { BADGE_REGISTRY_ADDRESS } from "@/lib/constants/blockchainConstants"; |
4 | | -import { badgeRegistryAbi } from "@/lib/abis/badgeRegistryAbi"; |
5 | | -import { stringToBytes32 } from "@/lib/utils/blockchainUtils"; |
| 5 | +import { |
| 6 | + badgeRegistryAbiV1, |
| 7 | + badgeRegistryAbiV2, |
| 8 | +} from "@/lib/abis/badgeRegistryAbi"; |
| 9 | +import { stringToBytes32, buildCreateBadgeArgs } from "@/lib/utils/blockchainUtils"; |
| 10 | +import { detectBadgeRegistryVersion } from "@/lib/badges/registryVersion"; |
6 | 11 |
|
7 | 12 | export function useCreateBadge() { |
| 13 | + const config = useConfig(); |
| 14 | + const { address: account, chainId } = useAccount(); |
8 | 15 | const { writeContractAsync, isPending, error, data, reset } = |
9 | 16 | useWriteContract(); |
10 | 17 |
|
11 | 18 | const createBadge = useMemo(() => { |
12 | 19 | return async (name: string, description: string) => { |
13 | | - if (!BADGE_REGISTRY_ADDRESS) throw new Error("Missing registry address"); |
| 20 | + if (!BADGE_REGISTRY_ADDRESS) { |
| 21 | + throw new Error("Badge registry address not configured"); |
| 22 | + } |
| 23 | + if (!account) { |
| 24 | + throw new Error("No wallet connected"); |
| 25 | + } |
| 26 | + if (!chainId) { |
| 27 | + throw new Error("No chain ID available"); |
| 28 | + } |
| 29 | + |
14 | 30 | const nameBytes = stringToBytes32(name); |
15 | | - const descriptionBytes = stringToBytes32(description); |
16 | | - return writeContractAsync({ |
17 | | - abi: badgeRegistryAbi, |
| 31 | + |
| 32 | + // Determine ABI mode deterministically BEFORE sending transaction |
| 33 | + // All version detection happens on-demand here to prevent refetch storm |
| 34 | + // Fetch totalBadges on-demand |
| 35 | + const totalBadgesResult = await readContract(config, { |
| 36 | + abi: badgeRegistryAbiV2, |
| 37 | + address: BADGE_REGISTRY_ADDRESS, |
| 38 | + functionName: "totalBadges", |
| 39 | + }); |
| 40 | + const currentCount = Number(totalBadgesResult ?? 0n); |
| 41 | + |
| 42 | + // TODO(cleanup-after-v2): Remove V1 fallback logic after V2 full deployment. Always use V2 ABI. See docs/V2_CLEANUP.md. |
| 43 | + const finalAbiMode = await detectBadgeRegistryVersion( |
| 44 | + config, |
| 45 | + account as `0x${string}`, |
| 46 | + chainId, |
| 47 | + currentCount |
| 48 | + ); |
| 49 | + |
| 50 | + // Now that ABI mode is determined, simulate and send with correct ABI |
| 51 | + const simulation = await simulateContract(config, { |
| 52 | + abi: finalAbiMode === "v2" ? badgeRegistryAbiV2 : badgeRegistryAbiV1, |
18 | 53 | address: BADGE_REGISTRY_ADDRESS, |
19 | 54 | functionName: "createBadge", |
20 | | - args: [nameBytes, descriptionBytes], |
| 55 | + args: buildCreateBadgeArgs(nameBytes, description, finalAbiMode), |
| 56 | + account: account as `0x${string}` | undefined, |
| 57 | + chainId, |
21 | 58 | }); |
| 59 | + |
| 60 | + // Single writeContractAsync call with correct ABI |
| 61 | + return await writeContractAsync(simulation.request); |
22 | 62 | }; |
23 | | - }, [writeContractAsync]); |
| 63 | + }, [writeContractAsync, account, chainId, config]); |
24 | 64 |
|
25 | 65 | const wait = useWaitForTransactionReceipt({ |
26 | 66 | hash: data as `0x${string}` | undefined, |
|
0 commit comments