I am tring to run a next app, but it is giving me the error “window is not defined”. I tried to fix it, but then it proceded to give me another error
My initial code:
store.tsx:
import { useEffect } from "react";
import { create } from "zustand";
import { EVMWallet } from "@catalogfi/wallets";
import { BrowserProvider,Wallet,JsonRpcProvider} from "ethers";
import { GardenJS } from "@gardenfi/core";
import { Orderbook, Chains,TESTNET_ORDERBOOK_API} from "@gardenfi/orderbook";
import {
BitcoinNetwork,
BitcoinProvider,
BitcoinOTA,
} from "@catalogfi/wallets";
type EvmWalletState = {
metaMaskIsConnected: boolean;
evmProvider: BrowserProvider | null;
};
type EvmWalletAction = {
connectMetaMask: () => Promise<void>;
};
const networkConfig = {
chainId: "0xaa36a7",
chainName: "Sepolia",
rpcUrls: ["https://sepolia.infura.io/v3/"],
nativeCurrency: {
symbol: "SepoliaETH",
decimals: 18,
},
};
const useMetaMaskStore = create<EvmWalletState & EvmWalletAction>((set) => ({
metaMaskIsConnected: false,
evmProvider: null,
connectMetaMask: async () => {
if (window.ethereum !== null) {
let provider = new BrowserProvider(window.ethereum);
let network = await provider.getNetwork();
console.log("network: ",network);
if (network.chainId !== 11155111n) {
await window.ethereum.request({
method: "wallet_addEthereumChain",
params: [networkConfig],
});
provider = new BrowserProvider(window.ethereum);
}
set(() => ({
evmProvider: provider,
metaMaskIsConnected: true,
}));
} else {
throw new Error("MetaMask not Found");
}
},
}));
const signer = await new BrowserProvider(window.ethereum).getSigner();
const evmWallet = new EVMWallet(signer);
const provider = new BitcoinProvider(BitcoinNetwork.Testnet);
//const signer = await new BrowserProvider(window.ethereum).getSigner();
const bitcoinWallet = new BitcoinOTA(provider, signer);
type GardenStore = {
garden: GardenJS | null;
bitcoin: BitcoinOTA | null;
ethereum: EVMWallet | null;
setGarden: (garden: GardenJS, bitcoin: BitcoinOTA, ethereum: EVMWallet) => void;
};
const gardenStore = create<GardenStore>((set) => ({
garden: null,
bitcoin: bitcoinWallet,
ethereum:evmWallet,
setGarden: (garden: GardenJS, bitcoin: BitcoinOTA,ethereum:EVMWallet) => {
set(() => ({
garden,
bitcoin,
ethereum
}));
},
}));
type SignStore = {
isMMPopupOpen: boolean;
isSigned: boolean;
setIsMMPopupOpen: (isMMPopupOpen: boolean) => void;
setIsSigned: (isSigned: boolean) => void;
};
const useSignStore = create<SignStore>((set) => ({
isMMPopupOpen: false,
isSigned: false,
setIsMMPopupOpen: (isMMPopupOpen: boolean) => {
set(() => {
return { isMMPopupOpen };
});
},
setIsSigned: (isSigned: boolean) => {
set(() => {
return { isSigned };
});
},
}));
const useGarden = () => ({
garden: gardenStore((state) => state.garden),
bitcoin: gardenStore((state) => state.bitcoin),
ethereum: gardenStore((state)=>state.ethereum)
});
/* Only to be used once at the root level*/
const useGardenSetup = () => {
const { evmProvider } = useMetaMaskStore();
const { setGarden } = gardenStore();
useEffect(() => {
(async () => {
if (!evmProvider) return;
const signer = await evmProvider.getSigner();
// const bitcoinProvider = new BitcoinProvider(
// BitcoinNetwork.Testnet,
// "http://localhost:30000"
// );
const orderbook = await Orderbook.init({
url: TESTNET_ORDERBOOK_API,
signer,
// opts: {
// // eslint-disable-next-line @typescript-eslint/no-explicit-any
// domain: (window as any).location.host,
// store: localStorage,
// },
});
const wallets = {
[Chains.bitcoin_testnet]: bitcoinWallet,
[Chains.ethereum_sepolia]: evmWallet,
};
const garden = new GardenJS(orderbook, wallets);
setGarden(garden, wallets[Chains.bitcoin_testnet],wallets[Chains.ethereum_sepolia]);
})();
}, [evmProvider, setGarden]);
};
export { useMetaMaskStore, useGarden, useGardenSetup, useSignStore };
I tried using typeof window !== “undefined” && window.ethereum !== null, but it is then giving the error once the initial error was fixed
1 of 3 unhandled errors
Unhandled Runtime Error
Error: Text content does not match server-rendered HTML.
Warning: Text content did not match. Server: "Token Details" Client: "Wrapped Tokens Import"
See more info here: https://nextjs.org/docs/messages/react-hydration-error
Component Stack
li
ol
Stepper
div
tokenize
StateContextProvider
AnonAadhaarProvider
Le
Web3ContextProvider
ConnectKitProvider
QueryClientProvider
Hydrate
WagmiProvider
Web3Provider
App
Call Stack
checkForUnmatchedText
node_modulesreact-domcjsreact-dom.development.js (9647:0)
didNotMatchHydratedTextInstance
node_modulesreact-domcjsreact-dom.development.js (11394:0)
prepareToHydrateHostTextInstance
node_modulesreact-domcjsreact-dom.development.js (12606:0)
completeWork
node_modulesreact-domcjsreact-dom.development.js (22232:0)
completeUnitOfWork
node_modulesreact-domcjsreact-dom.development.js (26596:0)
performUnitOfWork
node_modulesreact-domcjsreact-dom.development.js (26568:0)
workLoopSync
node_modulesreact-domcjsreact-dom.development.js (26466:0)
renderRootSync
node_modulesreact-domcjsreact-dom.development.js (26434:0)
performConcurrentWorkOnRoot
node_modulesreact-domcjsreact-dom.development.js (25738:0)
workLoop
node_modulesschedulercjsscheduler.development.js (266:0)
flushWork
node_modulesschedulercjsscheduler.development.js (239:0)
MessagePort.performWorkUntilDeadline
node_modulesschedulercjsscheduler.development.js (533:0)
tokenize.jsx:
import { useState } from "react";
import TokenDetailsComponent from "../Components/TokenDetailsComponent";
import ChooseChainComponent from "../Components/ChooseChainComponent";
import ToWBTCComponent from "./toWBTCComponent";
import { Button } from "flowbite-react";
import { useAccount } from "wagmi";
const Stepper = () => {
const [currentStep, setCurrentStep] = useState(1);
const account = useAccount();
const stepperOptions = [
{
label: 1,
value: 'Chain of Deployment'
},
{
label: 2,
value: 'Wrapped Tokens Import'
},
{
label: 3,
value: 'Token Details'
},
{
label: 4,
value: 'Confirmation'
}
];
const renderStepContent = () => {
switch(currentStep) {
case 1:
return <ChooseChainComponent />;
case 2:
return <ToWBTCComponent/>;
case 3:
return <TokenDetailsComponent />;
// Add cases for other steps as needed
default:
return null;
}
};
const handleNext = () => {
if (currentStep < stepperOptions.length) {
setCurrentStep(currentStep + 1);
}
};
const handlePrevious = () => {
if (currentStep > 1) {
setCurrentStep(currentStep - 1);
}
};
return (
<>
<ol className="flex items-center flex-row justify-center w-full p-3 space-x-2 text-sm font-medium text-center text-gray-500 dark:text-gray-400 sm:text-base sm:p-4 sm:space-x-4 rtl:space-x-reverse">
{stepperOptions.map((option, index) => {
if (option.label === 2 && account.chainId !== 11155111) {
// Do not render the "Wrapped Tokens Import" option if the selected chain is not Sepolia
return null;
}
return (
<li key={index} className={`flex items-center ${currentStep === option.label ? 'text-blue-600 dark:text-blue-500' : 'text-gray-500 dark:text-gray-400'}`}>
<span className="flex items-center justify-center w-5 h-5 me-2 text-xs border border-blue-600 rounded-full shrink-0 dark:border-blue-500">
{option.label > 2 ? (account.chainId === 11155111 ? option.label: option.label-1) : option.label}
</span>
{option.value}
{option.label !== 4 && (
<svg className="w-3 h-3 ms-2 sm:ms-4 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 12 10">
<path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="m7 9 4-4-4-4M1 9l4-4-4-4"/>
</svg>
)}
</li>
);
})}
</ol>
<div className="step-content">
{renderStepContent()}
</div>
<div className="flex flex-row items-center justify-between mt-4">
<Button color='purple' onClick={handlePrevious} disabled={currentStep === 1} className="btn btn-secondary">
Previous
</Button>
<Button color='purple' onClick={handleNext} disabled={currentStep === stepperOptions.length} className="btn btn-primary">
Next
</Button>
</div>
</>
);
}
export default Stepper;