I am using wagmi to connect my front-end to my Smart Contract written in Solidity. I wrote the connectors in my _app.js as well as the provider. And wrapped the App with wagmi, as shown below.
_app.js
export default function App({ Component, pageProps }) {
return (
<WagmiConfig client={client}>
<Component {...pageProps} />
</WagmiConfig>
)
}
I also imported everything into my .jsx file and started setting up the connection to my Smart Contract. Yesterday everything worked, but today my NextJS suddenly gives me the error:
Unhandled Runtime Error:
Error: Hydration failed because the initial UI does not match what was rendered on the server.
Warning: Expected server HTML to contain a matching <section> in <div>.
I get this error because I wrapped my code into try/catch.
Error code before wrapping the code with try/catch:
TypeError: Cannot read properties of null (reading 'id')
const { config } = usePrepareContractWrite({
| ^
36 | address: "0x....",
37 | abi: contractAbi,
38 | functionName: "functionName",
Unhandled Runtime Error
Error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.
Now as far as I understood and found out by following the error and looking into the hook itself, is that the hook is not reading the contract's chainId.
I exported the Contract's ABI and the Contract's Address like this:
const { ethers, network } = require("hardhat")
const fs = require("fs")
const FRONT_END_ADDRESSES_FILE = "/PATH/contractABI.json"
const FRONT_END_ABI_FILE = "/PATH/contractAdress.json"
module.exports = async function () {
if (process.env.UPDATE_FRONT_END) {
updateContractAddresses()
updateAbi()
}
}
async function updateAbi() {
const contract = await ethers.getContract("Contract")
fs.writeFileSync(FRONT_END_ABI_FILE, contract.interface.format(ethers.utils.FormatTypes.json))
}
async function updateContractAddresses() {
const contract = await ethers.getContract("Contract")
const chainId = network.config.chainId.toString()
const contractAddresses = JSON.parse(fs.readFileSync(FRONT_END_ADDRESSES_FILE), "utf8")
if (network.config.chainId.toString() in contractAddresses) {
if (!contractAddresses[chainId].includes(contract.address)) {
contractAddresses[chainId].push(contract.address)
}
} else {
contractAddresses[chainId] = [contract.address]
}
fs.writeFileSync(FRONT_END_ADDRESSES_FILE, JSON.stringify(contractAddresses))
}
module.exports.tags = ["all", "frontend"]
In the NextJS folder I made a folder, inside I made 3 files (contractAbi.json, contractAddresses.json, index.js). The ABI and the Address are successfully exported into these files, so that isn't the problem.
I also imported the contractAbi.json and contractAddresses.json into the _app.js.
The Error is supposed to be in the Header.jsx file.
Here are the imports from that file:
import { contractAbi, contractAddresses } from "../constants"
/* General Imports */
import { ethers } from "ethers"
import { useState, useEffect } from "react"
import {
useContract,
useAccount,
useConnect,
useDisconnect,
useContractRead,
useContractWrite,
usePrepareContractWrite,
useWaitForTransaction,
} from "wagmi"
Here is the Logic:
export default function Header() {
const { disconnect } = useDisconnect()
const { connector, address, isConnected } = useAccount()
const { connect, connectors, error, pendingConnector } = useConnect()
const { config } = usePrepareContractWrite({
address: "0x...............",
abi: contractAbi,
functionName: "functionName",
})
const { data: functionName, write } = useContractWrite(config)
const {
data: transactionResponse,
isSuccess,
isLoading,
} = useWaitForTransaction({
hash: functionName?.hash,
})
return (
<>
{connector ? (
<div className={styles.connectedTo}>
<button
className={`${styles2.btn} ${styles.connected}`}
onClick={() => disconnect()}
>
Connected:{" "}
<a
href={`https://etherscan.io/address/${address}`}
className={styles.connectedAddress}
>
{address.slice(0, 5) + "..." + address.slice(-4)}
</a>
</button>
</div>
) : (
<div className={styles.dropdown}>
<button className={`${styles2.btn} ${styles.navWallet}`}>
<span className={styles.notConnectedInfo}>Connect Wallet</span>
</button>
<div className={styles.wallets}>
<button
className={`${styles.wallet} ${styles.wallet1}`}
onClick={() => connect({ connector: connectors.metamask })}
>
<img
src="/img/metamask-original-48.png"
alt="Metamask Logo"
className={styles.walletIcon}
/>
</button>
<button
className={`${styles.wallet} ${styles.wallet2}`}
onClick={() => connect({ connector: connectors.coinbase })}
>
<img
src="/img/coinbase_png.png"
alt="Coinbase Logo"
className={styles.walletIcon}
/>
</button>
<button
className={`${styles.wallet} ${styles.wallet4}`}
onClick={() => connect({ connector: connectors.walletconnect })}
>
<img
src="/img/walletconnect_logo.png"
alt="WalletConnect Logo"
className={styles.walletIcon}
/>
</button>
<button
className={`${styles.wallet} ${styles.wallet5}`}
onClick={() => connect({ connector: connectors.ledger })}
>
<img src="img/Light-Icon.svg" alt="Ledger Logo" className={styles.walletIcon} />
</button>
<button
className={`${styles.wallet} ${styles.wallet6}`}
onClick={() => connect({ connector: connectors.safe })}
>
<img
src="/img/gnosis_safe.png"
alt="Gnosis Safe Logo"
className={styles.walletIcon}
/>
</button>
</div>
</div>
)}
</>
<>
<button
className={`${styles2.btn} ${styles.heroBtn}`}
disabled={!write || isLoading}
onClick={() => write?.()}
>
{isLoading ? "Pending..." : "Execute transaction"}
</button>
</>
)