From c8db0bfa57cf819ec58097b3c1ada62bfebf3ef7 Mon Sep 17 00:00:00 2001 From: karooolis Date: Fri, 13 Sep 2024 14:00:11 +0100 Subject: [PATCH 01/27] initial chain name as url refactoring --- examples/local-explorer/mprocs.yaml | 2 +- .../[worldAddress]/explore/DataExplorer.tsx | 0 .../explore/EditableTableCell.tsx | 10 +++---- .../[worldAddress]/explore/TableSelector.tsx | 2 +- .../[worldAddress]/explore/TablesViewer.tsx | 8 +++--- .../worlds/[worldAddress]/explore/page.tsx | 0 .../worlds/[worldAddress]/interact/Form.tsx | 12 ++++----- .../[worldAddress]/interact/FunctionField.tsx | 8 +++--- .../worlds/[worldAddress]/interact/page.tsx | 0 .../interact/useContractMutation.ts | 6 ++--- .../worlds/[worldAddress]/layout.tsx | 2 +- .../worlds/[worldAddress]/observe/Write.tsx | 2 +- .../worlds/[worldAddress]/observe/Writes.tsx | 4 +-- .../worlds/[worldAddress]/observe/common.ts | 0 .../worlds/[worldAddress]/observe/page.tsx | 0 .../(explorer)/worlds/[worldAddress]/page.tsx | 0 .../[worldAddress]/utils/bufferToBigInt.ts | 0 .../(explorer)/worlds/page.tsx | 0 .../{(explorer) => [chainName]}/Providers.tsx | 27 ++++++++++++++++++- .../app/{(explorer) => [chainName]}/error.tsx | 0 .../{(explorer) => [chainName]}/globals.css | 0 .../{(explorer) => [chainName]}/layout.tsx | 0 .../{(explorer) => [chainName]}/not-found.tsx | 0 .../app/{(explorer) => [chainName]}/page.tsx | 0 packages/explorer/src/common.ts | 7 +++++ 25 files changed, 61 insertions(+), 29 deletions(-) rename packages/explorer/src/app/{ => [chainName]}/(explorer)/worlds/[worldAddress]/explore/DataExplorer.tsx (100%) rename packages/explorer/src/app/{ => [chainName]}/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx (92%) rename packages/explorer/src/app/{ => [chainName]}/(explorer)/worlds/[worldAddress]/explore/TableSelector.tsx (96%) rename packages/explorer/src/app/{ => [chainName]}/(explorer)/worlds/[worldAddress]/explore/TablesViewer.tsx (96%) rename packages/explorer/src/app/{ => [chainName]}/(explorer)/worlds/[worldAddress]/explore/page.tsx (100%) rename packages/explorer/src/app/{ => [chainName]}/(explorer)/worlds/[worldAddress]/interact/Form.tsx (89%) rename packages/explorer/src/app/{ => [chainName]}/(explorer)/worlds/[worldAddress]/interact/FunctionField.tsx (93%) rename packages/explorer/src/app/{ => [chainName]}/(explorer)/worlds/[worldAddress]/interact/page.tsx (100%) rename packages/explorer/src/app/{ => [chainName]}/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts (95%) rename packages/explorer/src/app/{ => [chainName]}/(explorer)/worlds/[worldAddress]/layout.tsx (72%) rename packages/explorer/src/app/{ => [chainName]}/(explorer)/worlds/[worldAddress]/observe/Write.tsx (94%) rename packages/explorer/src/app/{ => [chainName]}/(explorer)/worlds/[worldAddress]/observe/Writes.tsx (84%) rename packages/explorer/src/app/{ => [chainName]}/(explorer)/worlds/[worldAddress]/observe/common.ts (100%) rename packages/explorer/src/app/{ => [chainName]}/(explorer)/worlds/[worldAddress]/observe/page.tsx (100%) rename packages/explorer/src/app/{ => [chainName]}/(explorer)/worlds/[worldAddress]/page.tsx (100%) rename packages/explorer/src/app/{ => [chainName]}/(explorer)/worlds/[worldAddress]/utils/bufferToBigInt.ts (100%) rename packages/explorer/src/app/{ => [chainName]}/(explorer)/worlds/page.tsx (100%) rename packages/explorer/src/app/{(explorer) => [chainName]}/Providers.tsx (65%) rename packages/explorer/src/app/{(explorer) => [chainName]}/error.tsx (100%) rename packages/explorer/src/app/{(explorer) => [chainName]}/globals.css (100%) rename packages/explorer/src/app/{(explorer) => [chainName]}/layout.tsx (100%) rename packages/explorer/src/app/{(explorer) => [chainName]}/not-found.tsx (100%) rename packages/explorer/src/app/{(explorer) => [chainName]}/page.tsx (100%) diff --git a/examples/local-explorer/mprocs.yaml b/examples/local-explorer/mprocs.yaml index d9e4b7ba0c..3e2fada672 100644 --- a/examples/local-explorer/mprocs.yaml +++ b/examples/local-explorer/mprocs.yaml @@ -18,4 +18,4 @@ procs: SQLITE_FILENAME: "indexer.db" explorer: cwd: packages/contracts - shell: pnpm explorer --dev + shell: pnpm explorer diff --git a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/explore/DataExplorer.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/DataExplorer.tsx similarity index 100% rename from packages/explorer/src/app/(explorer)/worlds/[worldAddress]/explore/DataExplorer.tsx rename to packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/DataExplorer.tsx diff --git a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx similarity index 92% rename from packages/explorer/src/app/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx rename to packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx index 45f493260f..cee10c3561 100644 --- a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx @@ -9,11 +9,11 @@ import { SchemaAbiType } from "@latticexyz/schema-type/internal"; import IBaseWorldAbi from "@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.json"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { waitForTransactionReceipt, writeContract } from "@wagmi/core"; -import { getChain } from "../../../../../common"; -import { Checkbox } from "../../../../../components/ui/Checkbox"; -import { camelCase, cn } from "../../../../../lib/utils"; -import { TableConfig } from "../../../../api/table/route"; -import { wagmiConfig } from "../../../Providers"; +import { getChain } from "../../../../../../common"; +import { Checkbox } from "../../../../../../components/ui/Checkbox"; +import { camelCase, cn } from "../../../../../../lib/utils"; +import { TableConfig } from "../../../../../api/table/route"; +import { wagmiConfig } from "../../../../Providers"; type Props = { name: string; diff --git a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/explore/TableSelector.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/TableSelector.tsx similarity index 96% rename from packages/explorer/src/app/(explorer)/worlds/[worldAddress]/explore/TableSelector.tsx rename to packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/TableSelector.tsx index 7bd6a8a05c..2429d9930a 100644 --- a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/explore/TableSelector.tsx +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/TableSelector.tsx @@ -1,7 +1,7 @@ import { Lock } from "lucide-react"; import { useParams } from "next/navigation"; import { internalTableNames } from "@latticexyz/store-sync/sqlite"; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../../../../components/ui/Select"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../../../../../components/ui/Select"; type Props = { value: string | undefined; diff --git a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/explore/TablesViewer.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/TablesViewer.tsx similarity index 96% rename from packages/explorer/src/app/(explorer)/worlds/[worldAddress]/explore/TablesViewer.tsx rename to packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/TablesViewer.tsx index d12254ae82..3d992be635 100644 --- a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/explore/TablesViewer.tsx +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/TablesViewer.tsx @@ -14,10 +14,10 @@ import { getSortedRowModel, useReactTable, } from "@tanstack/react-table"; -import { Button } from "../../../../../components/ui/Button"; -import { Checkbox } from "../../../../../components/ui/Checkbox"; -import { Input } from "../../../../../components/ui/Input"; -import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../../../../../components/ui/Table"; +import { Button } from "../../../../../../components/ui/Button"; +import { Checkbox } from "../../../../../../components/ui/Checkbox"; +import { Input } from "../../../../../../components/ui/Input"; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../../../../../../components/ui/Table"; import { bufferToBigInt } from "../utils/bufferToBigInt"; import { EditableTableCell } from "./EditableTableCell"; diff --git a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/explore/page.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/page.tsx similarity index 100% rename from packages/explorer/src/app/(explorer)/worlds/[worldAddress]/explore/page.tsx rename to packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/page.tsx diff --git a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/interact/Form.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/Form.tsx similarity index 89% rename from packages/explorer/src/app/(explorer)/worlds/[worldAddress]/interact/Form.tsx rename to packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/Form.tsx index 3c78302d5d..15521e3f2d 100644 --- a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/interact/Form.tsx +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/Form.tsx @@ -3,12 +3,12 @@ import { Coins, Eye, Send } from "lucide-react"; import { AbiFunction } from "viem"; import { useDeferredValue, useState } from "react"; -import { Input } from "../../../../../components/ui/Input"; -import { Separator } from "../../../../../components/ui/Separator"; -import { Skeleton } from "../../../../../components/ui/Skeleton"; -import { useHashState } from "../../../../../hooks/useHashState"; -import { cn } from "../../../../../lib/utils"; -import { useAbiQuery } from "../../../../../queries/useAbiQuery"; +import { Input } from "../../../../../../components/ui/Input"; +import { Separator } from "../../../../../../components/ui/Separator"; +import { Skeleton } from "../../../../../../components/ui/Skeleton"; +import { useHashState } from "../../../../../../hooks/useHashState"; +import { cn } from "../../../../../../lib/utils"; +import { useAbiQuery } from "../../../../../../queries/useAbiQuery"; import { FunctionField } from "./FunctionField"; export function Form() { diff --git a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/interact/FunctionField.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/FunctionField.tsx similarity index 93% rename from packages/explorer/src/app/(explorer)/worlds/[worldAddress]/interact/FunctionField.tsx rename to packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/FunctionField.tsx index ecb6affad2..0ca1bf7e8c 100644 --- a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/interact/FunctionField.tsx +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/FunctionField.tsx @@ -6,10 +6,10 @@ import { z } from "zod"; import { useState } from "react"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; -import { Button } from "../../../../../components/ui/Button"; -import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../../../../../components/ui/Form"; -import { Input } from "../../../../../components/ui/Input"; -import { Separator } from "../../../../../components/ui/Separator"; +import { Button } from "../../../../../../components/ui/Button"; +import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../../../../../../components/ui/Form"; +import { Input } from "../../../../../../components/ui/Input"; +import { Separator } from "../../../../../../components/ui/Separator"; import { useContractMutation } from "./useContractMutation"; export enum FunctionType { diff --git a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/interact/page.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/page.tsx similarity index 100% rename from packages/explorer/src/app/(explorer)/worlds/[worldAddress]/interact/page.tsx rename to packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/page.tsx diff --git a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts similarity index 95% rename from packages/explorer/src/app/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts rename to packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts index b877bfb81c..799d30d95e 100644 --- a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts @@ -4,8 +4,8 @@ import { Abi, AbiFunction, Hex } from "viem"; import { useAccount } from "wagmi"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { readContract, waitForTransactionReceipt, writeContract } from "@wagmi/core"; -import { getChain } from "../../../../../common"; -import { wagmiConfig } from "../../../Providers"; +import { getChain } from "../../../../../../common"; +import { wagmiConfig } from "../../../../Providers"; import { FunctionType } from "./FunctionField"; type UseContractMutationProps = { @@ -17,8 +17,8 @@ const chain = getChain(); const chainId = chain.id; export function useContractMutation({ abi, operationType }: UseContractMutationProps) { - const queryClient = useQueryClient(); const { worldAddress } = useParams(); + const queryClient = useQueryClient(); const account = useAccount(); return useMutation({ diff --git a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/layout.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/layout.tsx similarity index 72% rename from packages/explorer/src/app/(explorer)/worlds/[worldAddress]/layout.tsx rename to packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/layout.tsx index c13476dcf2..41d7d524bf 100644 --- a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/layout.tsx +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/layout.tsx @@ -1,6 +1,6 @@ "use client"; -import { Navigation } from "../../../../components/Navigation"; +import { Navigation } from "../../../../../components/Navigation"; export default function WorldLayout({ children }: { children: React.ReactNode }) { return ( diff --git a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/observe/Write.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/observe/Write.tsx similarity index 94% rename from packages/explorer/src/app/(explorer)/worlds/[worldAddress]/observe/Write.tsx rename to packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/observe/Write.tsx index b61825e5ce..daa8bdf225 100644 --- a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/observe/Write.tsx +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/observe/Write.tsx @@ -1,6 +1,6 @@ "use client"; -import { type Write } from "../../../../../observer/store"; +import { type Write } from "../../../../../../observer/store"; import { msPerViewportWidth } from "./common"; export type Props = Write; diff --git a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/observe/Writes.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/observe/Writes.tsx similarity index 84% rename from packages/explorer/src/app/(explorer)/worlds/[worldAddress]/observe/Writes.tsx rename to packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/observe/Writes.tsx index 053b509e28..821e849b34 100644 --- a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/observe/Writes.tsx +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/observe/Writes.tsx @@ -1,8 +1,8 @@ "use client"; import { useStore } from "zustand"; -import { KeepInView } from "../../../../../components/KeepInView"; -import { store } from "../../../../../observer/store"; +import { KeepInView } from "../../../../../../components/KeepInView"; +import { store } from "../../../../../../observer/store"; import { Write } from "./Write"; export function Writes() { diff --git a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/observe/common.ts b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/observe/common.ts similarity index 100% rename from packages/explorer/src/app/(explorer)/worlds/[worldAddress]/observe/common.ts rename to packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/observe/common.ts diff --git a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/observe/page.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/observe/page.tsx similarity index 100% rename from packages/explorer/src/app/(explorer)/worlds/[worldAddress]/observe/page.tsx rename to packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/observe/page.tsx diff --git a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/page.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/page.tsx similarity index 100% rename from packages/explorer/src/app/(explorer)/worlds/[worldAddress]/page.tsx rename to packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/page.tsx diff --git a/packages/explorer/src/app/(explorer)/worlds/[worldAddress]/utils/bufferToBigInt.ts b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/utils/bufferToBigInt.ts similarity index 100% rename from packages/explorer/src/app/(explorer)/worlds/[worldAddress]/utils/bufferToBigInt.ts rename to packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/utils/bufferToBigInt.ts diff --git a/packages/explorer/src/app/(explorer)/worlds/page.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/page.tsx similarity index 100% rename from packages/explorer/src/app/(explorer)/worlds/page.tsx rename to packages/explorer/src/app/[chainName]/(explorer)/worlds/page.tsx diff --git a/packages/explorer/src/app/(explorer)/Providers.tsx b/packages/explorer/src/app/[chainName]/Providers.tsx similarity index 65% rename from packages/explorer/src/app/(explorer)/Providers.tsx rename to packages/explorer/src/app/[chainName]/Providers.tsx index b2d407c0be..1690e18948 100644 --- a/packages/explorer/src/app/(explorer)/Providers.tsx +++ b/packages/explorer/src/app/[chainName]/Providers.tsx @@ -1,12 +1,13 @@ "use client"; +import { useParams } from "next/navigation"; import { WagmiProvider, createConfig, http } from "wagmi"; import { injected, metaMask, safe } from "wagmi/connectors"; import { ReactNode } from "react"; import { RainbowKitProvider, darkTheme } from "@rainbow-me/rainbowkit"; import "@rainbow-me/rainbowkit/styles.css"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; -import { getChain } from "../../common"; +import { getChain, namedChains } from "../../common"; import { defaultAnvilConnectors } from "../../connectors/anvil"; const queryClient = new QueryClient(); @@ -31,6 +32,30 @@ export const wagmiConfig = createConfig({ }); export function Providers({ children }: { children: ReactNode }) { + const { chainName } = useParams(); + const chain = namedChains[chainName as string]; + if (!chain) { + throw new Error(`Chain ${chainName} not supported`); + } + + const wagmiConfig = createConfig({ + chains: [chain], + connectors: [ + injected(), + metaMask({ + dappMetadata: { + name: "World Explorer", + }, + }), + safe(), + ...defaultAnvilConnectors, + ], + transports: { + [chain.id]: http(), + }, + ssr: true, + }); + return ( diff --git a/packages/explorer/src/app/(explorer)/error.tsx b/packages/explorer/src/app/[chainName]/error.tsx similarity index 100% rename from packages/explorer/src/app/(explorer)/error.tsx rename to packages/explorer/src/app/[chainName]/error.tsx diff --git a/packages/explorer/src/app/(explorer)/globals.css b/packages/explorer/src/app/[chainName]/globals.css similarity index 100% rename from packages/explorer/src/app/(explorer)/globals.css rename to packages/explorer/src/app/[chainName]/globals.css diff --git a/packages/explorer/src/app/(explorer)/layout.tsx b/packages/explorer/src/app/[chainName]/layout.tsx similarity index 100% rename from packages/explorer/src/app/(explorer)/layout.tsx rename to packages/explorer/src/app/[chainName]/layout.tsx diff --git a/packages/explorer/src/app/(explorer)/not-found.tsx b/packages/explorer/src/app/[chainName]/not-found.tsx similarity index 100% rename from packages/explorer/src/app/(explorer)/not-found.tsx rename to packages/explorer/src/app/[chainName]/not-found.tsx diff --git a/packages/explorer/src/app/(explorer)/page.tsx b/packages/explorer/src/app/[chainName]/page.tsx similarity index 100% rename from packages/explorer/src/app/(explorer)/page.tsx rename to packages/explorer/src/app/[chainName]/page.tsx diff --git a/packages/explorer/src/common.ts b/packages/explorer/src/common.ts index 22e27c0596..b6c432a928 100644 --- a/packages/explorer/src/common.ts +++ b/packages/explorer/src/common.ts @@ -1,5 +1,12 @@ import { Chain, anvil, garnet, redstone } from "viem/chains"; +// TODO: improve +export const namedChains: Partial> = { + anvil: anvil, + redstone: redstone, + garnet: garnet, +}; + export const chains: Partial> = { [anvil.id]: anvil, [redstone.id]: redstone, From 67d7279b9e2cb719303ffcf05e2679ee5b9c1d16 Mon Sep 17 00:00:00 2001 From: karooolis Date: Fri, 13 Sep 2024 17:20:09 +0100 Subject: [PATCH 02/27] fix nav urls --- packages/explorer/src/hooks/useWorldUrl.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/explorer/src/hooks/useWorldUrl.ts b/packages/explorer/src/hooks/useWorldUrl.ts index 5cb1254784..2225b79585 100644 --- a/packages/explorer/src/hooks/useWorldUrl.ts +++ b/packages/explorer/src/hooks/useWorldUrl.ts @@ -2,6 +2,6 @@ import { useParams } from "next/navigation"; export function useWorldUrl() { const params = useParams(); - const { worldAddress } = params; - return (page: string) => `/worlds/${worldAddress}/${page}`; + const { chainName, worldAddress } = params; + return (page: string) => `/${chainName}/worlds/${worldAddress}/${page}`; } From c8c26b8f9fb27c36eff75424a245b18e71430160 Mon Sep 17 00:00:00 2001 From: karooolis Date: Fri, 13 Sep 2024 17:57:42 +0100 Subject: [PATCH 03/27] redirect chain name --- .../(explorer)/worlds/[worldAddress]/page.tsx | 15 +++++- .../(explorer)/worlds/not-found.tsx | 28 +++++++++++ .../[chainName]/(explorer)/worlds/page.tsx | 10 +++- .../explorer/src/app/[chainName]/layout.tsx | 45 ++---------------- .../explorer/src/app/[chainName]/page.tsx | 11 ++++- .../src/app/{[chainName] => }/error.tsx | 4 +- .../src/app/{[chainName] => }/globals.css | 0 packages/explorer/src/app/layout.tsx | 46 +++++++++++++++++++ packages/explorer/src/app/not-found.tsx | 28 +++++++++++ packages/explorer/src/app/page.tsx | 15 ++++++ packages/explorer/src/bin/explorer.ts | 2 +- packages/explorer/src/common.ts | 14 ++++-- 12 files changed, 164 insertions(+), 54 deletions(-) create mode 100644 packages/explorer/src/app/[chainName]/(explorer)/worlds/not-found.tsx rename packages/explorer/src/app/{[chainName] => }/error.tsx (92%) rename packages/explorer/src/app/{[chainName] => }/globals.css (100%) create mode 100644 packages/explorer/src/app/layout.tsx create mode 100644 packages/explorer/src/app/not-found.tsx create mode 100644 packages/explorer/src/app/page.tsx diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/page.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/page.tsx index 2fedbf5643..b0733b07a3 100644 --- a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/page.tsx +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/page.tsx @@ -1,5 +1,16 @@ import { redirect } from "next/navigation"; -export default async function WorldPage({ params }: { params: { worldAddress: string } }) { - return redirect(`/worlds/${params.worldAddress}/explore`); +// TODO: move to common? +type ParamsProps = { + chainName: string; + worldAddress: string; +}; + +type Props = { + params: ParamsProps; +}; + +export default async function WorldPage({ params }: Props) { + const { chainName, worldAddress } = params; + return redirect(`/${chainName}/worlds/${worldAddress}/explore`); } diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/not-found.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/not-found.tsx new file mode 100644 index 0000000000..8bb2f71349 --- /dev/null +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/not-found.tsx @@ -0,0 +1,28 @@ +"use client"; + +import { ExternalLink } from "lucide-react"; +import Link from "next/link"; +import { Button } from "../../../../components/ui/Button"; +import { useWorldUrl } from "../../../../hooks/useWorldUrl"; + +export default function NotFound() { + const getUrl = useWorldUrl(); + return ( +
+

404

+

Page not found

+

Sorry, we couldn’t find the page you’re looking for.

+
+ + + +
+
+ ); +} diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/page.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/page.tsx index 02b20cad15..4358639446 100644 --- a/packages/explorer/src/app/[chainName]/(explorer)/worlds/page.tsx +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/page.tsx @@ -2,8 +2,14 @@ import { notFound, redirect } from "next/navigation"; export const dynamic = "force-dynamic"; -export default function WorldsPage() { +type Props = { + params: { + chainName: string; + }; +}; + +export default function WorldsPage({ params }: Props) { const worldAddress = process.env.WORLD_ADDRESS; - if (worldAddress) return redirect(`/worlds/${worldAddress}`); + if (worldAddress) return redirect(`/${params.chainName}/worlds/${worldAddress}`); return notFound(); } diff --git a/packages/explorer/src/app/[chainName]/layout.tsx b/packages/explorer/src/app/[chainName]/layout.tsx index 4bcb74b30b..c55496271b 100644 --- a/packages/explorer/src/app/[chainName]/layout.tsx +++ b/packages/explorer/src/app/[chainName]/layout.tsx @@ -1,49 +1,10 @@ -import type { Metadata } from "next"; -import { Inter, JetBrains_Mono } from "next/font/google"; -import { Toaster } from "sonner"; -import { Theme } from "@radix-ui/themes"; -import "@radix-ui/themes/styles.css"; import { Providers } from "./Providers"; -import "./globals.css"; -const inter = Inter({ - subsets: ["latin"], - display: "swap", - variable: "--font-inter", -}); - -const jetbrains = JetBrains_Mono({ - subsets: ["latin"], - variable: "--font-jetbrains-mono", -}); - -export const metadata: Metadata = { - title: "World Explorer", - description: "World Explorer is a tool for visually exploring and manipulating the state of worlds", -}; - -export default function RootLayout({ +// TODO: might not be needed, or could be moved elsewhere +export default function WorldsLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { - return ( - - - - -
- {children} -
- -
-
- - - ); + return {children}; } diff --git a/packages/explorer/src/app/[chainName]/page.tsx b/packages/explorer/src/app/[chainName]/page.tsx index cd0a8af1d8..741be4aa64 100644 --- a/packages/explorer/src/app/[chainName]/page.tsx +++ b/packages/explorer/src/app/[chainName]/page.tsx @@ -1,5 +1,12 @@ import { redirect } from "next/navigation"; -export default async function IndexPage() { - redirect("/worlds"); +// TODO: can params be dynamically extracted +type Props = { + params: { + chainName: string; + }; +}; + +export default async function ChainPage({ params }: Props) { + return redirect(`/${params.chainName}/worlds`); } diff --git a/packages/explorer/src/app/[chainName]/error.tsx b/packages/explorer/src/app/error.tsx similarity index 92% rename from packages/explorer/src/app/[chainName]/error.tsx rename to packages/explorer/src/app/error.tsx index 4cfe8b5711..844d3e5723 100644 --- a/packages/explorer/src/app/[chainName]/error.tsx +++ b/packages/explorer/src/app/error.tsx @@ -2,8 +2,8 @@ import { ExternalLink, RefreshCwIcon } from "lucide-react"; import Link from "next/link"; -import { Button } from "../../components/ui/Button"; -import { useWorldUrl } from "../../hooks/useWorldUrl"; +import { Button } from "../components/ui/Button"; +import { useWorldUrl } from "../hooks/useWorldUrl"; type Props = { error: Error & { digest?: string }; diff --git a/packages/explorer/src/app/[chainName]/globals.css b/packages/explorer/src/app/globals.css similarity index 100% rename from packages/explorer/src/app/[chainName]/globals.css rename to packages/explorer/src/app/globals.css diff --git a/packages/explorer/src/app/layout.tsx b/packages/explorer/src/app/layout.tsx new file mode 100644 index 0000000000..533d78abcf --- /dev/null +++ b/packages/explorer/src/app/layout.tsx @@ -0,0 +1,46 @@ +import type { Metadata } from "next"; +import { Inter, JetBrains_Mono } from "next/font/google"; +import { Toaster } from "sonner"; +import { Theme } from "@radix-ui/themes"; +import "@radix-ui/themes/styles.css"; +import "./globals.css"; + +const inter = Inter({ + subsets: ["latin"], + display: "swap", + variable: "--font-inter", +}); + +const jetbrains = JetBrains_Mono({ + subsets: ["latin"], + variable: "--font-jetbrains-mono", +}); + +export const metadata: Metadata = { + title: "World Explorer", + description: "World Explorer is a tool for visually exploring and manipulating the state of worlds", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + +
+ {children} +
+ +
+ + + ); +} diff --git a/packages/explorer/src/app/not-found.tsx b/packages/explorer/src/app/not-found.tsx new file mode 100644 index 0000000000..a4cddf5996 --- /dev/null +++ b/packages/explorer/src/app/not-found.tsx @@ -0,0 +1,28 @@ +"use client"; + +import { ExternalLink } from "lucide-react"; +import Link from "next/link"; +import { Button } from "../components/ui/Button"; +import { useWorldUrl } from "../hooks/useWorldUrl"; + +export default function NotFound() { + const getUrl = useWorldUrl(); + return ( +
+

404

+

Page not found

+

Sorry, we couldn’t find the page you’re looking for.

+
+ + + +
+
+ ); +} diff --git a/packages/explorer/src/app/page.tsx b/packages/explorer/src/app/page.tsx new file mode 100644 index 0000000000..40481257be --- /dev/null +++ b/packages/explorer/src/app/page.tsx @@ -0,0 +1,15 @@ +import { notFound, redirect } from "next/navigation"; +import { chainsNamesMap } from "../common"; + +export const dynamic = "force-dynamic"; + +export default function IndexPage() { + const chainId = Number(process.env.CHAIN_ID); + const chainName = chainsNamesMap[chainId]; + + if (chainName) { + // TODO: improve + return redirect(`/${chainName}/worlds`); + } + return notFound(); +} diff --git a/packages/explorer/src/bin/explorer.ts b/packages/explorer/src/bin/explorer.ts index 8362863d61..7ba860a75d 100755 --- a/packages/explorer/src/bin/explorer.ts +++ b/packages/explorer/src/bin/explorer.ts @@ -71,7 +71,7 @@ let explorerProcess: ChildProcess; async function startExplorer() { const env = { ...process.env, - NEXT_PUBLIC_CHAIN_ID: chainId.toString(), + CHAIN_ID: chainId.toString(), WORLD_ADDRESS: worldAddress?.toString(), INDEXER_DATABASE: path.join(process.cwd(), indexerDatabase), }; diff --git a/packages/explorer/src/common.ts b/packages/explorer/src/common.ts index b6c432a928..9e45071882 100644 --- a/packages/explorer/src/common.ts +++ b/packages/explorer/src/common.ts @@ -1,20 +1,28 @@ import { Chain, anvil, garnet, redstone } from "viem/chains"; +// TODO: improve naming +export const chainsNamesMap = { + [anvil.id]: "anvil", + [garnet.id]: "garnet", + [redstone.id]: "redstone", +}; + // TODO: improve export const namedChains: Partial> = { anvil: anvil, - redstone: redstone, garnet: garnet, + redstone: redstone, }; export const chains: Partial> = { [anvil.id]: anvil, - [redstone.id]: redstone, [garnet.id]: garnet, + [redstone.id]: redstone, }; export function getChain() { - const chainId = Number(process.env.NEXT_PUBLIC_CHAIN_ID || anvil.id); + // TODO: handle differently, might need to be removed + const chainId = Number(process.env.CHAIN_ID || anvil.id); const chain = chains[chainId]; if (!chain) { throw new Error(`Chain ID ${chainId} not supported. Supported chains are: ${Object.keys(chains).join(", ")}.`); From a0d2f8399b4b4570d780b47c4ee5c0d1581566ad Mon Sep 17 00:00:00 2001 From: karooolis Date: Fri, 13 Sep 2024 18:13:05 +0100 Subject: [PATCH 04/27] use wagmi config from useConfig --- examples/local-explorer/mprocs.yaml | 2 +- .../explore/EditableTableCell.tsx | 12 ++++------ .../interact/useContractMutation.ts | 14 ++++------- .../src/app/[chainName]/Providers.tsx | 23 +++---------------- .../explorer/src/app/[chainName]/layout.tsx | 1 - packages/explorer/src/app/page.tsx | 7 ++---- 6 files changed, 15 insertions(+), 44 deletions(-) diff --git a/examples/local-explorer/mprocs.yaml b/examples/local-explorer/mprocs.yaml index 3e2fada672..d9e4b7ba0c 100644 --- a/examples/local-explorer/mprocs.yaml +++ b/examples/local-explorer/mprocs.yaml @@ -18,4 +18,4 @@ procs: SQLITE_FILENAME: "indexer.db" explorer: cwd: packages/contracts - shell: pnpm explorer + shell: pnpm explorer --dev diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx index cee10c3561..afae087ec9 100644 --- a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx @@ -2,18 +2,16 @@ import { Loader } from "lucide-react"; import { useParams } from "next/navigation"; import { toast } from "sonner"; import { Hex } from "viem"; -import { useAccount } from "wagmi"; +import { useAccount, useConfig } from "wagmi"; import { ChangeEvent, useState } from "react"; import { encodeField, getFieldIndex } from "@latticexyz/protocol-parser/internal"; import { SchemaAbiType } from "@latticexyz/schema-type/internal"; import IBaseWorldAbi from "@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.json"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { waitForTransactionReceipt, writeContract } from "@wagmi/core"; -import { getChain } from "../../../../../../common"; import { Checkbox } from "../../../../../../components/ui/Checkbox"; import { camelCase, cn } from "../../../../../../lib/utils"; import { TableConfig } from "../../../../../api/table/route"; -import { wagmiConfig } from "../../../../Providers"; type Props = { name: string; @@ -22,10 +20,8 @@ type Props = { config: TableConfig; }; -const chain = getChain(); -const chainId = chain.id; - export function EditableTableCell({ name, config, keyTuple, value: defaultValue }: Props) { + const wagmiConfig = useConfig(); const queryClient = useQueryClient(); const { worldAddress } = useParams(); const account = useAccount(); @@ -44,7 +40,7 @@ export function EditableTableCell({ name, config, keyTuple, value: defaultValue address: worldAddress as Hex, functionName: "setField", args: [tableId, keyTuple, fieldIndex, encodedField], - chainId, + chainId: 31337, // TODO: change }); const receipt = await waitForTransactionReceipt(wagmiConfig, { @@ -68,7 +64,7 @@ export function EditableTableCell({ name, config, keyTuple, value: defaultValue "balance", { address: account.address, - chainId, + chainId: 31337, // TODO: change }, ], }); diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts index 799d30d95e..ad62e206d5 100644 --- a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts @@ -1,11 +1,9 @@ import { useParams } from "next/navigation"; import { toast } from "sonner"; import { Abi, AbiFunction, Hex } from "viem"; -import { useAccount } from "wagmi"; +import { useAccount, useConfig } from "wagmi"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { readContract, waitForTransactionReceipt, writeContract } from "@wagmi/core"; -import { getChain } from "../../../../../../common"; -import { wagmiConfig } from "../../../../Providers"; import { FunctionType } from "./FunctionField"; type UseContractMutationProps = { @@ -13,12 +11,10 @@ type UseContractMutationProps = { operationType: FunctionType; }; -const chain = getChain(); -const chainId = chain.id; - export function useContractMutation({ abi, operationType }: UseContractMutationProps) { const { worldAddress } = useParams(); const queryClient = useQueryClient(); + const wagmiConfig = useConfig(); const account = useAccount(); return useMutation({ @@ -29,7 +25,7 @@ export function useContractMutation({ abi, operationType }: UseContractMutationP address: worldAddress as Hex, functionName: abi.name, args: inputs, - chainId, + chainId: 31337, // TODO: change }); return { result }; @@ -40,7 +36,7 @@ export function useContractMutation({ abi, operationType }: UseContractMutationP functionName: abi.name, args: inputs, ...(value && { value: BigInt(value) }), - chainId, + chainId: 31337, // TODO: change }); const receipt = await waitForTransactionReceipt(wagmiConfig, { @@ -69,7 +65,7 @@ export function useContractMutation({ abi, operationType }: UseContractMutationP "balance", { address: account, - chainId, + chainId: 31337, // TODO: change }, ], }); diff --git a/packages/explorer/src/app/[chainName]/Providers.tsx b/packages/explorer/src/app/[chainName]/Providers.tsx index 1690e18948..03d7cbdd54 100644 --- a/packages/explorer/src/app/[chainName]/Providers.tsx +++ b/packages/explorer/src/app/[chainName]/Providers.tsx @@ -7,30 +7,11 @@ import { ReactNode } from "react"; import { RainbowKitProvider, darkTheme } from "@rainbow-me/rainbowkit"; import "@rainbow-me/rainbowkit/styles.css"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; -import { getChain, namedChains } from "../../common"; +import { namedChains } from "../../common"; import { defaultAnvilConnectors } from "../../connectors/anvil"; const queryClient = new QueryClient(); -const chain = getChain(); -export const wagmiConfig = createConfig({ - chains: [chain], - connectors: [ - injected(), - metaMask({ - dappMetadata: { - name: "World Explorer", - }, - }), - safe(), - ...defaultAnvilConnectors, - ], - transports: { - [chain.id]: http(), - }, - ssr: true, -}); - export function Providers({ children }: { children: ReactNode }) { const { chainName } = useParams(); const chain = namedChains[chainName as string]; @@ -56,6 +37,8 @@ export function Providers({ children }: { children: ReactNode }) { ssr: true, }); + console.log(chain); + return ( diff --git a/packages/explorer/src/app/[chainName]/layout.tsx b/packages/explorer/src/app/[chainName]/layout.tsx index c55496271b..46f7c14b27 100644 --- a/packages/explorer/src/app/[chainName]/layout.tsx +++ b/packages/explorer/src/app/[chainName]/layout.tsx @@ -1,6 +1,5 @@ import { Providers } from "./Providers"; -// TODO: might not be needed, or could be moved elsewhere export default function WorldsLayout({ children, }: Readonly<{ diff --git a/packages/explorer/src/app/page.tsx b/packages/explorer/src/app/page.tsx index 40481257be..ddbece48d2 100644 --- a/packages/explorer/src/app/page.tsx +++ b/packages/explorer/src/app/page.tsx @@ -5,11 +5,8 @@ export const dynamic = "force-dynamic"; export default function IndexPage() { const chainId = Number(process.env.CHAIN_ID); - const chainName = chainsNamesMap[chainId]; + const chainName = chainsNamesMap[chainId]; // TODO: TS - if (chainName) { - // TODO: improve - return redirect(`/${chainName}/worlds`); - } + if (chainName) return redirect(`/${chainName}/worlds`); return notFound(); } From 632cd2368119ce7602e8022fd6db4c60ba8cb893 Mon Sep 17 00:00:00 2001 From: karooolis Date: Fri, 13 Sep 2024 18:16:48 +0100 Subject: [PATCH 05/27] use chain id from url params --- .../worlds/[worldAddress]/explore/EditableTableCell.tsx | 6 ++++-- .../worlds/[worldAddress]/interact/useContractMutation.ts | 8 +++++--- packages/explorer/src/hooks/useChainId.ts | 8 ++++++++ 3 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 packages/explorer/src/hooks/useChainId.ts diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx index afae087ec9..afcec8f676 100644 --- a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx @@ -10,6 +10,7 @@ import IBaseWorldAbi from "@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.j import { useMutation, useQueryClient } from "@tanstack/react-query"; import { waitForTransactionReceipt, writeContract } from "@wagmi/core"; import { Checkbox } from "../../../../../../components/ui/Checkbox"; +import { useChainId } from "../../../../../../hooks/useChainId"; import { camelCase, cn } from "../../../../../../lib/utils"; import { TableConfig } from "../../../../../api/table/route"; @@ -24,6 +25,7 @@ export function EditableTableCell({ name, config, keyTuple, value: defaultValue const wagmiConfig = useConfig(); const queryClient = useQueryClient(); const { worldAddress } = useParams(); + const chainId = useChainId(); const account = useAccount(); const [value, setValue] = useState(defaultValue); @@ -40,7 +42,7 @@ export function EditableTableCell({ name, config, keyTuple, value: defaultValue address: worldAddress as Hex, functionName: "setField", args: [tableId, keyTuple, fieldIndex, encodedField], - chainId: 31337, // TODO: change + chainId, }); const receipt = await waitForTransactionReceipt(wagmiConfig, { @@ -64,7 +66,7 @@ export function EditableTableCell({ name, config, keyTuple, value: defaultValue "balance", { address: account.address, - chainId: 31337, // TODO: change + chainId, }, ], }); diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts index ad62e206d5..c9cfe4e50a 100644 --- a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts @@ -4,6 +4,7 @@ import { Abi, AbiFunction, Hex } from "viem"; import { useAccount, useConfig } from "wagmi"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { readContract, waitForTransactionReceipt, writeContract } from "@wagmi/core"; +import { useChainId } from "../../../../../../hooks/useChainId"; import { FunctionType } from "./FunctionField"; type UseContractMutationProps = { @@ -13,6 +14,7 @@ type UseContractMutationProps = { export function useContractMutation({ abi, operationType }: UseContractMutationProps) { const { worldAddress } = useParams(); + const chainId = useChainId(); const queryClient = useQueryClient(); const wagmiConfig = useConfig(); const account = useAccount(); @@ -25,7 +27,7 @@ export function useContractMutation({ abi, operationType }: UseContractMutationP address: worldAddress as Hex, functionName: abi.name, args: inputs, - chainId: 31337, // TODO: change + chainId, }); return { result }; @@ -36,7 +38,7 @@ export function useContractMutation({ abi, operationType }: UseContractMutationP functionName: abi.name, args: inputs, ...(value && { value: BigInt(value) }), - chainId: 31337, // TODO: change + chainId, }); const receipt = await waitForTransactionReceipt(wagmiConfig, { @@ -65,7 +67,7 @@ export function useContractMutation({ abi, operationType }: UseContractMutationP "balance", { address: account, - chainId: 31337, // TODO: change + chainId, }, ], }); diff --git a/packages/explorer/src/hooks/useChainId.ts b/packages/explorer/src/hooks/useChainId.ts new file mode 100644 index 0000000000..5e00f263df --- /dev/null +++ b/packages/explorer/src/hooks/useChainId.ts @@ -0,0 +1,8 @@ +import { useParams } from "next/navigation"; +import { namedChains } from "../common"; + +export function useChainId() { + const params = useParams(); + const { chainName } = params; + return namedChains[chainName]; // TODO: TS +} From 552a1c2cad03a1d9b9a96a5d77e5c7dbb10f3e30 Mon Sep 17 00:00:00 2001 From: karooolis Date: Fri, 13 Sep 2024 18:34:20 +0100 Subject: [PATCH 06/27] dynamically set anvil connectors --- .../src/app/[chainName]/Providers.tsx | 6 ++--- packages/explorer/src/app/api/world/route.ts | 17 ++++++------ packages/explorer/src/app/page.tsx | 4 +-- packages/explorer/src/common.ts | 26 +++++-------------- packages/explorer/src/connectors/anvil.ts | 15 ++++++----- packages/explorer/src/hooks/useChainId.ts | 4 ++- packages/explorer/src/queries/useAbiQuery.ts | 12 +++++---- 7 files changed, 39 insertions(+), 45 deletions(-) diff --git a/packages/explorer/src/app/[chainName]/Providers.tsx b/packages/explorer/src/app/[chainName]/Providers.tsx index 03d7cbdd54..27a7b671b1 100644 --- a/packages/explorer/src/app/[chainName]/Providers.tsx +++ b/packages/explorer/src/app/[chainName]/Providers.tsx @@ -8,7 +8,7 @@ import { RainbowKitProvider, darkTheme } from "@rainbow-me/rainbowkit"; import "@rainbow-me/rainbowkit/styles.css"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { namedChains } from "../../common"; -import { defaultAnvilConnectors } from "../../connectors/anvil"; +import { getDefaultAnvilConnectors } from "../../connectors/anvil"; const queryClient = new QueryClient(); @@ -29,7 +29,7 @@ export function Providers({ children }: { children: ReactNode }) { }, }), safe(), - ...defaultAnvilConnectors, + ...getDefaultAnvilConnectors(chain.id), ], transports: { [chain.id]: http(), @@ -37,8 +37,6 @@ export function Providers({ children }: { children: ReactNode }) { ssr: true, }); - console.log(chain); - return ( diff --git a/packages/explorer/src/app/api/world/route.ts b/packages/explorer/src/app/api/world/route.ts index a0be3b52c2..38395865bc 100644 --- a/packages/explorer/src/app/api/world/route.ts +++ b/packages/explorer/src/app/api/world/route.ts @@ -3,21 +3,21 @@ import { getBlockNumber, getLogs } from "viem/actions"; import { helloStoreEvent } from "@latticexyz/store"; import { helloWorldEvent } from "@latticexyz/world"; import { getWorldAbi } from "@latticexyz/world/internal"; -import { getChain } from "../../../common"; +import { chains } from "../../../common"; export const dynamic = "force-dynamic"; -async function getClient() { +async function getClient(chainId: number) { const client = createWalletClient({ - chain: getChain(), + chain: chains[chainId], transport: http(), }); return client; } -async function getParameters(worldAddress: Address) { - const client = await getClient(); +async function getParameters(chainId: number, worldAddress: Address) { + const client = await getClient(chainId); const toBlock = await getBlockNumber(client); const logs = await getLogs(client, { strict: true, @@ -35,15 +35,16 @@ async function getParameters(worldAddress: Address) { export async function GET(req: Request) { const { searchParams } = new URL(req.url); - const worldAddress = searchParams.get("address") as Hex; + const worldAddress = searchParams.get("worldAddress") as Hex; + const chainId = Number(searchParams.get("chainId")); if (!worldAddress) { return Response.json({ error: "address is required" }, { status: 400 }); } try { - const client = await getClient(); - const { fromBlock, toBlock, isWorldDeployed } = await getParameters(worldAddress); + const client = await getClient(chainId); + const { fromBlock, toBlock, isWorldDeployed } = await getParameters(chainId, worldAddress); const worldAbiResponse = await getWorldAbi({ client, worldAddress, diff --git a/packages/explorer/src/app/page.tsx b/packages/explorer/src/app/page.tsx index ddbece48d2..e184937e99 100644 --- a/packages/explorer/src/app/page.tsx +++ b/packages/explorer/src/app/page.tsx @@ -1,11 +1,11 @@ import { notFound, redirect } from "next/navigation"; -import { chainsNamesMap } from "../common"; +import { chainNameId } from "../common"; export const dynamic = "force-dynamic"; export default function IndexPage() { const chainId = Number(process.env.CHAIN_ID); - const chainName = chainsNamesMap[chainId]; // TODO: TS + const chainName = chainNameId[chainId]; // TODO: TS if (chainName) return redirect(`/${chainName}/worlds`); return notFound(); diff --git a/packages/explorer/src/common.ts b/packages/explorer/src/common.ts index 9e45071882..4cb7d9bd3f 100644 --- a/packages/explorer/src/common.ts +++ b/packages/explorer/src/common.ts @@ -1,7 +1,7 @@ import { Chain, anvil, garnet, redstone } from "viem/chains"; -// TODO: improve naming -export const chainsNamesMap = { +// TODO: can be improved? +export const chainNameId = { [anvil.id]: "anvil", [garnet.id]: "garnet", [redstone.id]: "redstone", @@ -9,9 +9,9 @@ export const chainsNamesMap = { // TODO: improve export const namedChains: Partial> = { - anvil: anvil, - garnet: garnet, - redstone: redstone, + [chainNameId[anvil.id]]: anvil, + [chainNameId[garnet.id]]: garnet, + [chainNameId[redstone.id]]: redstone, }; export const chains: Partial> = { @@ -20,18 +20,6 @@ export const chains: Partial> = { [redstone.id]: redstone, }; -export function getChain() { - // TODO: handle differently, might need to be removed - const chainId = Number(process.env.CHAIN_ID || anvil.id); - const chain = chains[chainId]; - if (!chain) { - throw new Error(`Chain ID ${chainId} not supported. Supported chains are: ${Object.keys(chains).join(", ")}.`); - } - - return chain; -} - -export function isAnvil() { - const chain = getChain(); - return chain.id === anvil.id; +export function isAnvil(chainId: number) { + return chainId === anvil.id; } diff --git a/packages/explorer/src/connectors/anvil.ts b/packages/explorer/src/connectors/anvil.ts index 9a3a8ad66a..b7199a8a3a 100644 --- a/packages/explorer/src/connectors/anvil.ts +++ b/packages/explorer/src/connectors/anvil.ts @@ -2,7 +2,6 @@ import { EIP1193RequestFn, Transport, WalletRpcSchema, http } from "viem"; import { Account, privateKeyToAccount } from "viem/accounts"; import { anvil as anvilChain } from "viem/chains"; import { Connector, createConnector } from "wagmi"; -import { isAnvil } from "../common"; export const defaultAnvilAccounts = ( [ @@ -27,19 +26,23 @@ export type AnvilConnectorOptions = { id: string; name: string; accounts: readonly Account[]; + disabled: boolean; }; // We can't programmatically switch accounts within a connector, but we can switch between connectors, // so create one anvil connector per default anvil account so users can switch between default anvil accounts. -export const defaultAnvilConnectors = defaultAnvilAccounts.map((account, i) => - anvil({ id: `anvil-${i}`, name: `Anvil #${i + 1}`, accounts: [account] }), -); +export const getDefaultAnvilConnectors = (chainId: number) => { + const disabled = chainId !== anvilChain.id; + return defaultAnvilAccounts.map((account, i) => + anvil({ id: `anvil-${i}`, name: `Anvil #${i + 1}`, accounts: [account], disabled }), + ); +}; export function isAnvilConnector(connector: Connector): connector is AnvilConnector { return connector.type === "anvil"; } -export function anvil({ id, name, accounts }: AnvilConnectorOptions) { +export function anvil({ id, name, accounts, disabled }: AnvilConnectorOptions) { if (!accounts.length) throw new Error("missing accounts"); type Provider = ReturnType>>; @@ -70,7 +73,7 @@ export function anvil({ id, name, accounts }: AnvilConnectorOptions) { return http()({ chain: anvilChain }); }, async isAuthorized() { - if (!isAnvil()) return false; + if (disabled) return false; if (!connected) return false; const accounts = await this.getAccounts(); diff --git a/packages/explorer/src/hooks/useChainId.ts b/packages/explorer/src/hooks/useChainId.ts index 5e00f263df..a936afb5d0 100644 --- a/packages/explorer/src/hooks/useChainId.ts +++ b/packages/explorer/src/hooks/useChainId.ts @@ -4,5 +4,7 @@ import { namedChains } from "../common"; export function useChainId() { const params = useParams(); const { chainName } = params; - return namedChains[chainName]; // TODO: TS + const chain = namedChains[chainName]; // TODO: make a getter? + + return chain.id; // TODO: TS } diff --git a/packages/explorer/src/queries/useAbiQuery.ts b/packages/explorer/src/queries/useAbiQuery.ts index abe5ffb91c..63b3128999 100644 --- a/packages/explorer/src/queries/useAbiQuery.ts +++ b/packages/explorer/src/queries/useAbiQuery.ts @@ -1,11 +1,11 @@ import { useParams } from "next/navigation"; import { AbiFunction, Hex } from "viem"; import { UseQueryResult, useQuery } from "@tanstack/react-query"; +import { useChainId } from "../hooks/useChainId"; -export async function getAbi(worldAddress: Hex) { - const res = await fetch(`/api/world?${new URLSearchParams({ address: worldAddress })}`); +export async function getAbi(chainId: number, worldAddress: Hex) { + const res = await fetch(`/api/world?${new URLSearchParams({ chainId: String(chainId), worldAddress })}`); const data = await res.json(); - if (!res.ok) { throw new Error(data.error); } @@ -20,9 +20,11 @@ type AbiQueryResult = { export const useAbiQuery = (): UseQueryResult => { const { worldAddress } = useParams(); + const chainId = useChainId(); + return useQuery({ - queryKey: ["abi", worldAddress], - queryFn: () => getAbi(worldAddress as Hex), + queryKey: ["abi", chainId, worldAddress], + queryFn: () => getAbi(chainId, worldAddress as Hex), select: (data) => { return { abi: data.abi || [], From b7e2520f87dedda62534466dc5dea39fe6c8ed10 Mon Sep 17 00:00:00 2001 From: karooolis Date: Fri, 13 Sep 2024 19:50:54 +0100 Subject: [PATCH 07/27] check isAnvil in ConnectButton --- packages/explorer/src/components/ConnectButton.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/explorer/src/components/ConnectButton.tsx b/packages/explorer/src/components/ConnectButton.tsx index 5b544254f4..c296da9798 100644 --- a/packages/explorer/src/components/ConnectButton.tsx +++ b/packages/explorer/src/components/ConnectButton.tsx @@ -1,11 +1,16 @@ import { PlugIcon, ZapIcon } from "lucide-react"; +import { anvil } from "viem/chains"; import { ConnectButton as RainbowConnectButton } from "@rainbow-me/rainbowkit"; -import { isAnvil } from "../common"; +import { useChainId } from "../hooks/useChainId"; import { cn } from "../lib/utils"; import { AccountSelect } from "./AccountSelect"; import { Button } from "./ui/Button"; export function ConnectButton() { + const chainId = useChainId(); + // TODO: can be improved? + const isAnvil = chainId === anvil.id; + return ( {({ account, chain, openAccountModal, openChainModal, openConnectModal, mounted }) => { @@ -19,7 +24,7 @@ export function ConnectButton() { > {(() => { if (!connected) { - if (isAnvil()) { + if (isAnvil) { return ; } From 03e36e1ea65224f5d4de6e8b17869533a5ae8780 Mon Sep 17 00:00:00 2001 From: karooolis Date: Fri, 13 Sep 2024 19:52:53 +0100 Subject: [PATCH 08/27] check isAnvil in ConnectButton --- packages/explorer/src/components/ConnectButton.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/explorer/src/components/ConnectButton.tsx b/packages/explorer/src/components/ConnectButton.tsx index c296da9798..db25c855f9 100644 --- a/packages/explorer/src/components/ConnectButton.tsx +++ b/packages/explorer/src/components/ConnectButton.tsx @@ -8,9 +8,6 @@ import { Button } from "./ui/Button"; export function ConnectButton() { const chainId = useChainId(); - // TODO: can be improved? - const isAnvil = chainId === anvil.id; - return ( {({ account, chain, openAccountModal, openChainModal, openConnectModal, mounted }) => { @@ -24,7 +21,7 @@ export function ConnectButton() { > {(() => { if (!connected) { - if (isAnvil) { + if (chainId === anvil.id) { return ; } From c6c1252c7aafed87b4658621a67d473e45adb015 Mon Sep 17 00:00:00 2001 From: karooolis Date: Fri, 13 Sep 2024 20:52:38 +0100 Subject: [PATCH 09/27] useChain helper --- .../explore/EditableTableCell.tsx | 2 +- .../interact/useContractMutation.ts | 2 +- .../src/app/[chainName]/Providers.tsx | 10 +++----- packages/explorer/src/app/api/world/route.ts | 4 ++-- packages/explorer/src/app/page.tsx | 4 ++-- packages/explorer/src/bin/explorer.ts | 5 ++-- packages/explorer/src/common.ts | 23 +++++++++++-------- .../explorer/src/components/ConnectButton.tsx | 2 +- packages/explorer/src/hooks/useChainId.ts | 10 -------- packages/explorer/src/queries/useAbiQuery.ts | 2 +- 10 files changed, 28 insertions(+), 36 deletions(-) delete mode 100644 packages/explorer/src/hooks/useChainId.ts diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx index afcec8f676..259f1dcd0c 100644 --- a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx @@ -10,7 +10,7 @@ import IBaseWorldAbi from "@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.j import { useMutation, useQueryClient } from "@tanstack/react-query"; import { waitForTransactionReceipt, writeContract } from "@wagmi/core"; import { Checkbox } from "../../../../../../components/ui/Checkbox"; -import { useChainId } from "../../../../../../hooks/useChainId"; +import { useChainId } from "../../../../../../hooks/useChain"; import { camelCase, cn } from "../../../../../../lib/utils"; import { TableConfig } from "../../../../../api/table/route"; diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts index c9cfe4e50a..4ece341f70 100644 --- a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts @@ -4,7 +4,7 @@ import { Abi, AbiFunction, Hex } from "viem"; import { useAccount, useConfig } from "wagmi"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { readContract, waitForTransactionReceipt, writeContract } from "@wagmi/core"; -import { useChainId } from "../../../../../../hooks/useChainId"; +import { useChainId } from "../../../../../../hooks/useChain"; import { FunctionType } from "./FunctionField"; type UseContractMutationProps = { diff --git a/packages/explorer/src/app/[chainName]/Providers.tsx b/packages/explorer/src/app/[chainName]/Providers.tsx index 27a7b671b1..a77c8112c5 100644 --- a/packages/explorer/src/app/[chainName]/Providers.tsx +++ b/packages/explorer/src/app/[chainName]/Providers.tsx @@ -1,23 +1,18 @@ "use client"; -import { useParams } from "next/navigation"; import { WagmiProvider, createConfig, http } from "wagmi"; import { injected, metaMask, safe } from "wagmi/connectors"; import { ReactNode } from "react"; import { RainbowKitProvider, darkTheme } from "@rainbow-me/rainbowkit"; import "@rainbow-me/rainbowkit/styles.css"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; -import { namedChains } from "../../common"; import { getDefaultAnvilConnectors } from "../../connectors/anvil"; +import { useChain } from "../../hooks/useChain"; const queryClient = new QueryClient(); export function Providers({ children }: { children: ReactNode }) { - const { chainName } = useParams(); - const chain = namedChains[chainName as string]; - if (!chain) { - throw new Error(`Chain ${chainName} not supported`); - } + const chain = useChain(); const wagmiConfig = createConfig({ chains: [chain], @@ -29,6 +24,7 @@ export function Providers({ children }: { children: ReactNode }) { }, }), safe(), + // TODO: needs to be a function? ...getDefaultAnvilConnectors(chain.id), ], transports: { diff --git a/packages/explorer/src/app/api/world/route.ts b/packages/explorer/src/app/api/world/route.ts index 38395865bc..609763a786 100644 --- a/packages/explorer/src/app/api/world/route.ts +++ b/packages/explorer/src/app/api/world/route.ts @@ -3,13 +3,13 @@ import { getBlockNumber, getLogs } from "viem/actions"; import { helloStoreEvent } from "@latticexyz/store"; import { helloWorldEvent } from "@latticexyz/world"; import { getWorldAbi } from "@latticexyz/world/internal"; -import { chains } from "../../../common"; +import { SupportedChainIds, chains } from "../../../common"; export const dynamic = "force-dynamic"; async function getClient(chainId: number) { const client = createWalletClient({ - chain: chains[chainId], + chain: chains[chainId as SupportedChainIds], // TODO: type-check better transport: http(), }); diff --git a/packages/explorer/src/app/page.tsx b/packages/explorer/src/app/page.tsx index e184937e99..c3e8c91d47 100644 --- a/packages/explorer/src/app/page.tsx +++ b/packages/explorer/src/app/page.tsx @@ -1,11 +1,11 @@ import { notFound, redirect } from "next/navigation"; -import { chainNameId } from "../common"; +import { SupportedChainIds, chainIdName } from "../common"; export const dynamic = "force-dynamic"; export default function IndexPage() { const chainId = Number(process.env.CHAIN_ID); - const chainName = chainNameId[chainId]; // TODO: TS + const chainName = chainIdName[chainId as SupportedChainIds]; // TODO: type-check if (chainName) return redirect(`/${chainName}/worlds`); return notFound(); diff --git a/packages/explorer/src/bin/explorer.ts b/packages/explorer/src/bin/explorer.ts index 7ba860a75d..288cba8f8a 100755 --- a/packages/explorer/src/bin/explorer.ts +++ b/packages/explorer/src/bin/explorer.ts @@ -6,7 +6,7 @@ import process from "process"; import { fileURLToPath } from "url"; import yargs from "yargs"; import { ChildProcess, spawn } from "child_process"; -import { chains } from "../common"; +import { SupportedChainIds, chains } from "../common"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -57,7 +57,8 @@ const argv = yargs(process.argv.slice(2)) }, }) .check((argv) => { - if (!chains[Number(argv.chainId)]) { + // TODO: typecheck better + if (!chains[Number(argv.chainId) as SupportedChainIds]) { throw new Error(`Invalid chain ID. Supported chains are: ${Object.keys(chains).join(", ")}.`); } return true; diff --git a/packages/explorer/src/common.ts b/packages/explorer/src/common.ts index 4cb7d9bd3f..b1340920d3 100644 --- a/packages/explorer/src/common.ts +++ b/packages/explorer/src/common.ts @@ -1,25 +1,30 @@ import { Chain, anvil, garnet, redstone } from "viem/chains"; -// TODO: can be improved? -export const chainNameId = { +const supportedChains = [anvil, garnet, redstone]; + +export type SupportedChainIds = (typeof supportedChains)[number]["id"]; +export type SupportedChainNames = "anvil" | "garnet" | "redstone"; + +export const chainIdName: Record = { [anvil.id]: "anvil", [garnet.id]: "garnet", [redstone.id]: "redstone", -}; +} as const; -// TODO: improve -export const namedChains: Partial> = { - [chainNameId[anvil.id]]: anvil, - [chainNameId[garnet.id]]: garnet, - [chainNameId[redstone.id]]: redstone, +// TODO: construct dynamically TS +export const chainNameId: Record = { + anvil: anvil.id, + garnet: garnet.id, + redstone: redstone.id, }; -export const chains: Partial> = { +export const chains: Record = { [anvil.id]: anvil, [garnet.id]: garnet, [redstone.id]: redstone, }; +// TODO: remove entirely? export function isAnvil(chainId: number) { return chainId === anvil.id; } diff --git a/packages/explorer/src/components/ConnectButton.tsx b/packages/explorer/src/components/ConnectButton.tsx index db25c855f9..b274063de0 100644 --- a/packages/explorer/src/components/ConnectButton.tsx +++ b/packages/explorer/src/components/ConnectButton.tsx @@ -1,7 +1,7 @@ import { PlugIcon, ZapIcon } from "lucide-react"; import { anvil } from "viem/chains"; import { ConnectButton as RainbowConnectButton } from "@rainbow-me/rainbowkit"; -import { useChainId } from "../hooks/useChainId"; +import { useChainId } from "../hooks/useChain"; import { cn } from "../lib/utils"; import { AccountSelect } from "./AccountSelect"; import { Button } from "./ui/Button"; diff --git a/packages/explorer/src/hooks/useChainId.ts b/packages/explorer/src/hooks/useChainId.ts deleted file mode 100644 index a936afb5d0..0000000000 --- a/packages/explorer/src/hooks/useChainId.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { useParams } from "next/navigation"; -import { namedChains } from "../common"; - -export function useChainId() { - const params = useParams(); - const { chainName } = params; - const chain = namedChains[chainName]; // TODO: make a getter? - - return chain.id; // TODO: TS -} diff --git a/packages/explorer/src/queries/useAbiQuery.ts b/packages/explorer/src/queries/useAbiQuery.ts index 63b3128999..b474efcf7c 100644 --- a/packages/explorer/src/queries/useAbiQuery.ts +++ b/packages/explorer/src/queries/useAbiQuery.ts @@ -1,7 +1,7 @@ import { useParams } from "next/navigation"; import { AbiFunction, Hex } from "viem"; import { UseQueryResult, useQuery } from "@tanstack/react-query"; -import { useChainId } from "../hooks/useChainId"; +import { useChainId } from "../hooks/useChain"; export async function getAbi(chainId: number, worldAddress: Hex) { const res = await fetch(`/api/world?${new URLSearchParams({ chainId: String(chainId), worldAddress })}`); From af9dfe1347e77d4c457a8b665508429ffb2aa771 Mon Sep 17 00:00:00 2001 From: karooolis Date: Fri, 13 Sep 2024 20:52:51 +0100 Subject: [PATCH 10/27] useChain helper --- packages/explorer/src/hooks/useChain.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 packages/explorer/src/hooks/useChain.ts diff --git a/packages/explorer/src/hooks/useChain.ts b/packages/explorer/src/hooks/useChain.ts new file mode 100644 index 0000000000..330af3ddb7 --- /dev/null +++ b/packages/explorer/src/hooks/useChain.ts @@ -0,0 +1,20 @@ +import { useParams } from "next/navigation"; +import { SupportedChainNames, chainNameId, chains } from "../common"; + +export function useChain() { + const { chainName } = useParams(); + + // TODO: validate chainName TS + const chainId = chainNameId[chainName as SupportedChainNames]; + if (!chainId) { + throw new Error(`Invalid chain ID. Supported chains are: ${Object.keys(chains).join(", ")}.`); + } + + const chain = chains[chainId]; + return chain; +} + +export function useChainId() { + const chain = useChain(); + return chain.id; +} From f91da90fc6de9a04ec4444ab0eafc44d3808e28f Mon Sep 17 00:00:00 2001 From: karooolis Date: Mon, 16 Sep 2024 13:44:22 +0300 Subject: [PATCH 11/27] fix 404 and error pages, add favicon --- .../explore/EditableTableCell.tsx | 2 +- .../interact/useContractMutation.ts | 2 +- .../(explorer)/worlds/not-found.tsx | 28 ---------- .../src/app/[chainName]/Providers.tsx | 4 +- .../src/app/[chainName]/not-found.tsx | 28 ---------- packages/explorer/src/app/icon.svg | 55 +++++++++++++++++++ packages/explorer/src/connectors/anvil.ts | 1 + packages/explorer/src/queries/useAbiQuery.ts | 2 +- 8 files changed, 60 insertions(+), 62 deletions(-) delete mode 100644 packages/explorer/src/app/[chainName]/(explorer)/worlds/not-found.tsx delete mode 100644 packages/explorer/src/app/[chainName]/not-found.tsx create mode 100644 packages/explorer/src/app/icon.svg diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx index 259f1dcd0c..4c3fa2a7f8 100644 --- a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx @@ -25,7 +25,7 @@ export function EditableTableCell({ name, config, keyTuple, value: defaultValue const wagmiConfig = useConfig(); const queryClient = useQueryClient(); const { worldAddress } = useParams(); - const chainId = useChainId(); + const chainId = useChainId("editable-table-cell"); const account = useAccount(); const [value, setValue] = useState(defaultValue); diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts index 4ece341f70..4be4acfc4e 100644 --- a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts @@ -14,7 +14,7 @@ type UseContractMutationProps = { export function useContractMutation({ abi, operationType }: UseContractMutationProps) { const { worldAddress } = useParams(); - const chainId = useChainId(); + const chainId = useChainId("use-contract-mutation"); const queryClient = useQueryClient(); const wagmiConfig = useConfig(); const account = useAccount(); diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/not-found.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/not-found.tsx deleted file mode 100644 index 8bb2f71349..0000000000 --- a/packages/explorer/src/app/[chainName]/(explorer)/worlds/not-found.tsx +++ /dev/null @@ -1,28 +0,0 @@ -"use client"; - -import { ExternalLink } from "lucide-react"; -import Link from "next/link"; -import { Button } from "../../../../components/ui/Button"; -import { useWorldUrl } from "../../../../hooks/useWorldUrl"; - -export default function NotFound() { - const getUrl = useWorldUrl(); - return ( -
-

404

-

Page not found

-

Sorry, we couldn’t find the page you’re looking for.

-
- - - -
-
- ); -} diff --git a/packages/explorer/src/app/[chainName]/Providers.tsx b/packages/explorer/src/app/[chainName]/Providers.tsx index a77c8112c5..ad5ddd000b 100644 --- a/packages/explorer/src/app/[chainName]/Providers.tsx +++ b/packages/explorer/src/app/[chainName]/Providers.tsx @@ -12,8 +12,7 @@ import { useChain } from "../../hooks/useChain"; const queryClient = new QueryClient(); export function Providers({ children }: { children: ReactNode }) { - const chain = useChain(); - + const chain = useChain("providers"); const wagmiConfig = createConfig({ chains: [chain], connectors: [ @@ -24,7 +23,6 @@ export function Providers({ children }: { children: ReactNode }) { }, }), safe(), - // TODO: needs to be a function? ...getDefaultAnvilConnectors(chain.id), ], transports: { diff --git a/packages/explorer/src/app/[chainName]/not-found.tsx b/packages/explorer/src/app/[chainName]/not-found.tsx deleted file mode 100644 index 44059b412c..0000000000 --- a/packages/explorer/src/app/[chainName]/not-found.tsx +++ /dev/null @@ -1,28 +0,0 @@ -"use client"; - -import { ExternalLink } from "lucide-react"; -import Link from "next/link"; -import { Button } from "../../components/ui/Button"; -import { useWorldUrl } from "../../hooks/useWorldUrl"; - -export default function NotFound() { - const getUrl = useWorldUrl(); - return ( -
-

404

-

Page not found

-

Sorry, we couldn’t find the page you’re looking for.

-
- - - -
-
- ); -} diff --git a/packages/explorer/src/app/icon.svg b/packages/explorer/src/app/icon.svg new file mode 100644 index 0000000000..55f3761258 --- /dev/null +++ b/packages/explorer/src/app/icon.svg @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/explorer/src/connectors/anvil.ts b/packages/explorer/src/connectors/anvil.ts index b7199a8a3a..54bd3878b0 100644 --- a/packages/explorer/src/connectors/anvil.ts +++ b/packages/explorer/src/connectors/anvil.ts @@ -32,6 +32,7 @@ export type AnvilConnectorOptions = { // We can't programmatically switch accounts within a connector, but we can switch between connectors, // so create one anvil connector per default anvil account so users can switch between default anvil accounts. export const getDefaultAnvilConnectors = (chainId: number) => { + // disable anvil connector if chainId is not anvil const disabled = chainId !== anvilChain.id; return defaultAnvilAccounts.map((account, i) => anvil({ id: `anvil-${i}`, name: `Anvil #${i + 1}`, accounts: [account], disabled }), diff --git a/packages/explorer/src/queries/useAbiQuery.ts b/packages/explorer/src/queries/useAbiQuery.ts index b474efcf7c..4676ae9448 100644 --- a/packages/explorer/src/queries/useAbiQuery.ts +++ b/packages/explorer/src/queries/useAbiQuery.ts @@ -20,7 +20,7 @@ type AbiQueryResult = { export const useAbiQuery = (): UseQueryResult => { const { worldAddress } = useParams(); - const chainId = useChainId(); + const chainId = useChainId("use-abi-query"); return useQuery({ queryKey: ["abi", chainId, worldAddress], From a0fa83040aac86e0aedbbd271c5bb5f1f85397fd Mon Sep 17 00:00:00 2001 From: karooolis Date: Mon, 16 Sep 2024 13:46:51 +0300 Subject: [PATCH 12/27] remove isAnvil helper --- packages/explorer/src/common.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/explorer/src/common.ts b/packages/explorer/src/common.ts index b1340920d3..7c6b6ecd89 100644 --- a/packages/explorer/src/common.ts +++ b/packages/explorer/src/common.ts @@ -23,8 +23,3 @@ export const chains: Record = { [garnet.id]: garnet, [redstone.id]: redstone, }; - -// TODO: remove entirely? -export function isAnvil(chainId: number) { - return chainId === anvil.id; -} From 025af622bbeaf2b6e881fc724d50e7c14ee2c7a8 Mon Sep 17 00:00:00 2001 From: karooolis Date: Mon, 16 Sep 2024 14:22:50 +0300 Subject: [PATCH 13/27] add chain id + name validation --- .../[worldAddress]/explore/EditableTableCell.tsx | 2 +- .../interact/useContractMutation.ts | 2 +- .../explorer/src/app/[chainName]/Providers.tsx | 2 +- packages/explorer/src/app/page.tsx | 10 ++++++---- packages/explorer/src/common.ts | 15 +++++++++++++-- packages/explorer/src/hooks/useChain.ts | 10 ++++------ packages/explorer/src/queries/useAbiQuery.ts | 2 +- 7 files changed, 27 insertions(+), 16 deletions(-) diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx index 4c3fa2a7f8..259f1dcd0c 100644 --- a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx @@ -25,7 +25,7 @@ export function EditableTableCell({ name, config, keyTuple, value: defaultValue const wagmiConfig = useConfig(); const queryClient = useQueryClient(); const { worldAddress } = useParams(); - const chainId = useChainId("editable-table-cell"); + const chainId = useChainId(); const account = useAccount(); const [value, setValue] = useState(defaultValue); diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts index 4be4acfc4e..4ece341f70 100644 --- a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts @@ -14,7 +14,7 @@ type UseContractMutationProps = { export function useContractMutation({ abi, operationType }: UseContractMutationProps) { const { worldAddress } = useParams(); - const chainId = useChainId("use-contract-mutation"); + const chainId = useChainId(); const queryClient = useQueryClient(); const wagmiConfig = useConfig(); const account = useAccount(); diff --git a/packages/explorer/src/app/[chainName]/Providers.tsx b/packages/explorer/src/app/[chainName]/Providers.tsx index ad5ddd000b..5c90007d16 100644 --- a/packages/explorer/src/app/[chainName]/Providers.tsx +++ b/packages/explorer/src/app/[chainName]/Providers.tsx @@ -12,7 +12,7 @@ import { useChain } from "../../hooks/useChain"; const queryClient = new QueryClient(); export function Providers({ children }: { children: ReactNode }) { - const chain = useChain("providers"); + const chain = useChain(); const wagmiConfig = createConfig({ chains: [chain], connectors: [ diff --git a/packages/explorer/src/app/page.tsx b/packages/explorer/src/app/page.tsx index c3e8c91d47..c9bcc4c7ae 100644 --- a/packages/explorer/src/app/page.tsx +++ b/packages/explorer/src/app/page.tsx @@ -1,12 +1,14 @@ import { notFound, redirect } from "next/navigation"; -import { SupportedChainIds, chainIdName } from "../common"; +import { SupportedChainIds, chainIdName, isValidChainId } from "../common"; export const dynamic = "force-dynamic"; export default function IndexPage() { const chainId = Number(process.env.CHAIN_ID); - const chainName = chainIdName[chainId as SupportedChainIds]; // TODO: type-check + if (!isValidChainId(chainId)) { + return notFound(); + } - if (chainName) return redirect(`/${chainName}/worlds`); - return notFound(); + const chainName = chainIdName[chainId as SupportedChainIds]; + return redirect(`/${chainName}/worlds`); } diff --git a/packages/explorer/src/common.ts b/packages/explorer/src/common.ts index 7c6b6ecd89..c09146578f 100644 --- a/packages/explorer/src/common.ts +++ b/packages/explorer/src/common.ts @@ -5,13 +5,12 @@ const supportedChains = [anvil, garnet, redstone]; export type SupportedChainIds = (typeof supportedChains)[number]["id"]; export type SupportedChainNames = "anvil" | "garnet" | "redstone"; -export const chainIdName: Record = { +export const chainIdName: Record = { [anvil.id]: "anvil", [garnet.id]: "garnet", [redstone.id]: "redstone", } as const; -// TODO: construct dynamically TS export const chainNameId: Record = { anvil: anvil.id, garnet: garnet.id, @@ -23,3 +22,15 @@ export const chains: Record = { [garnet.id]: garnet, [redstone.id]: redstone, }; + +export function isValidChainId(chainId: number): chainId is SupportedChainIds { + return chainId in chainIdName; +} + +export function isValidChainName(name: string | string[] | undefined): name is SupportedChainNames { + if (Array.isArray(name)) { + return false; + } + + return typeof name === "string" && name in chainNameId; +} diff --git a/packages/explorer/src/hooks/useChain.ts b/packages/explorer/src/hooks/useChain.ts index 330af3ddb7..dfba4f0d96 100644 --- a/packages/explorer/src/hooks/useChain.ts +++ b/packages/explorer/src/hooks/useChain.ts @@ -1,15 +1,13 @@ import { useParams } from "next/navigation"; -import { SupportedChainNames, chainNameId, chains } from "../common"; +import { chainNameId, chains, isValidChainName } from "../common"; export function useChain() { const { chainName } = useParams(); - - // TODO: validate chainName TS - const chainId = chainNameId[chainName as SupportedChainNames]; - if (!chainId) { - throw new Error(`Invalid chain ID. Supported chains are: ${Object.keys(chains).join(", ")}.`); + if (!isValidChainName(chainName)) { + throw new Error(`Invalid chain name. Supported chains are: ${Object.keys(chainNameId).join(", ")}.`); } + const chainId = chainNameId[chainName]; const chain = chains[chainId]; return chain; } diff --git a/packages/explorer/src/queries/useAbiQuery.ts b/packages/explorer/src/queries/useAbiQuery.ts index 4676ae9448..b474efcf7c 100644 --- a/packages/explorer/src/queries/useAbiQuery.ts +++ b/packages/explorer/src/queries/useAbiQuery.ts @@ -20,7 +20,7 @@ type AbiQueryResult = { export const useAbiQuery = (): UseQueryResult => { const { worldAddress } = useParams(); - const chainId = useChainId("use-abi-query"); + const chainId = useChainId(); return useQuery({ queryKey: ["abi", chainId, worldAddress], From 3009ef449e54cf5e09719753a2be5d1093aa3158 Mon Sep 17 00:00:00 2001 From: karooolis Date: Mon, 16 Sep 2024 14:26:14 +0300 Subject: [PATCH 14/27] use asserts for chain checking --- packages/explorer/src/app/page.tsx | 6 ++---- packages/explorer/src/common.ts | 14 +++++++------- packages/explorer/src/hooks/useChain.ts | 4 +--- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/packages/explorer/src/app/page.tsx b/packages/explorer/src/app/page.tsx index c9bcc4c7ae..e477f1caea 100644 --- a/packages/explorer/src/app/page.tsx +++ b/packages/explorer/src/app/page.tsx @@ -1,13 +1,11 @@ -import { notFound, redirect } from "next/navigation"; +import { redirect } from "next/navigation"; import { SupportedChainIds, chainIdName, isValidChainId } from "../common"; export const dynamic = "force-dynamic"; export default function IndexPage() { const chainId = Number(process.env.CHAIN_ID); - if (!isValidChainId(chainId)) { - return notFound(); - } + isValidChainId(chainId); const chainName = chainIdName[chainId as SupportedChainIds]; return redirect(`/${chainName}/worlds`); diff --git a/packages/explorer/src/common.ts b/packages/explorer/src/common.ts index c09146578f..5e47d81ab2 100644 --- a/packages/explorer/src/common.ts +++ b/packages/explorer/src/common.ts @@ -23,14 +23,14 @@ export const chains: Record = { [redstone.id]: redstone, }; -export function isValidChainId(chainId: number): chainId is SupportedChainIds { - return chainId in chainIdName; +export function isValidChainId(chainId: number): asserts chainId is SupportedChainIds { + if (!(chainId in chainIdName)) { + throw new Error(`Invalid chain id. Supported chains are: ${Object.keys(chainIdName).join(", ")}.`); + } } -export function isValidChainName(name: string | string[] | undefined): name is SupportedChainNames { - if (Array.isArray(name)) { - return false; +export function isValidChainName(name: string | string[] | undefined): asserts name is SupportedChainNames { + if (Array.isArray(name) || typeof name !== "string" || !(name in chainNameId)) { + throw new Error(`Invalid chain name. Supported chains are: ${Object.keys(chainNameId).join(", ")}.`); } - - return typeof name === "string" && name in chainNameId; } diff --git a/packages/explorer/src/hooks/useChain.ts b/packages/explorer/src/hooks/useChain.ts index dfba4f0d96..a36f628e27 100644 --- a/packages/explorer/src/hooks/useChain.ts +++ b/packages/explorer/src/hooks/useChain.ts @@ -3,9 +3,7 @@ import { chainNameId, chains, isValidChainName } from "../common"; export function useChain() { const { chainName } = useParams(); - if (!isValidChainName(chainName)) { - throw new Error(`Invalid chain name. Supported chains are: ${Object.keys(chainNameId).join(", ")}.`); - } + isValidChainName(chainName); const chainId = chainNameId[chainName]; const chain = chains[chainId]; From ea4573b77a198c91020efb939c392e0554005379 Mon Sep 17 00:00:00 2001 From: karooolis Date: Mon, 16 Sep 2024 14:36:24 +0300 Subject: [PATCH 15/27] typecheck chain id within router --- .../(explorer)/worlds/[worldAddress]/page.tsx | 11 ++++------- packages/explorer/src/app/[chainName]/page.tsx | 1 - packages/explorer/src/app/api/world/route.ts | 8 +++++--- packages/explorer/src/bin/explorer.ts | 7 ++----- 4 files changed, 11 insertions(+), 16 deletions(-) diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/page.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/page.tsx index b0733b07a3..47b435ef54 100644 --- a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/page.tsx +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/page.tsx @@ -1,13 +1,10 @@ import { redirect } from "next/navigation"; -// TODO: move to common? -type ParamsProps = { - chainName: string; - worldAddress: string; -}; - type Props = { - params: ParamsProps; + params: { + chainName: string; + worldAddress: string; + }; }; export default async function WorldPage({ params }: Props) { diff --git a/packages/explorer/src/app/[chainName]/page.tsx b/packages/explorer/src/app/[chainName]/page.tsx index 741be4aa64..e6c8fd70b9 100644 --- a/packages/explorer/src/app/[chainName]/page.tsx +++ b/packages/explorer/src/app/[chainName]/page.tsx @@ -1,6 +1,5 @@ import { redirect } from "next/navigation"; -// TODO: can params be dynamically extracted type Props = { params: { chainName: string; diff --git a/packages/explorer/src/app/api/world/route.ts b/packages/explorer/src/app/api/world/route.ts index 609763a786..eadb1e134d 100644 --- a/packages/explorer/src/app/api/world/route.ts +++ b/packages/explorer/src/app/api/world/route.ts @@ -3,13 +3,13 @@ import { getBlockNumber, getLogs } from "viem/actions"; import { helloStoreEvent } from "@latticexyz/store"; import { helloWorldEvent } from "@latticexyz/world"; import { getWorldAbi } from "@latticexyz/world/internal"; -import { SupportedChainIds, chains } from "../../../common"; +import { SupportedChainIds, chains, isValidChainId } from "../../../common"; export const dynamic = "force-dynamic"; -async function getClient(chainId: number) { +async function getClient(chainId: SupportedChainIds) { const client = createWalletClient({ - chain: chains[chainId as SupportedChainIds], // TODO: type-check better + chain: chains[chainId], transport: http(), }); @@ -17,6 +17,8 @@ async function getClient(chainId: number) { } async function getParameters(chainId: number, worldAddress: Address) { + isValidChainId(chainId); + const client = await getClient(chainId); const toBlock = await getBlockNumber(client); const logs = await getLogs(client, { diff --git a/packages/explorer/src/bin/explorer.ts b/packages/explorer/src/bin/explorer.ts index 288cba8f8a..15c996b19f 100755 --- a/packages/explorer/src/bin/explorer.ts +++ b/packages/explorer/src/bin/explorer.ts @@ -6,7 +6,7 @@ import process from "process"; import { fileURLToPath } from "url"; import yargs from "yargs"; import { ChildProcess, spawn } from "child_process"; -import { SupportedChainIds, chains } from "../common"; +import { isValidChainId } from "../common"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -57,10 +57,7 @@ const argv = yargs(process.argv.slice(2)) }, }) .check((argv) => { - // TODO: typecheck better - if (!chains[Number(argv.chainId) as SupportedChainIds]) { - throw new Error(`Invalid chain ID. Supported chains are: ${Object.keys(chains).join(", ")}.`); - } + isValidChainId(Number(argv.chainId)); return true; }) .parseSync(); From 9c64ecee796e89596a09d0bfba9b874fd1cb2240 Mon Sep 17 00:00:00 2001 From: karooolis Date: Mon, 16 Sep 2024 14:39:05 +0300 Subject: [PATCH 16/27] typecheck chain id within router --- packages/explorer/src/app/api/world/route.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/explorer/src/app/api/world/route.ts b/packages/explorer/src/app/api/world/route.ts index eadb1e134d..e399362663 100644 --- a/packages/explorer/src/app/api/world/route.ts +++ b/packages/explorer/src/app/api/world/route.ts @@ -16,9 +16,7 @@ async function getClient(chainId: SupportedChainIds) { return client; } -async function getParameters(chainId: number, worldAddress: Address) { - isValidChainId(chainId); - +async function getParameters(chainId: SupportedChainIds, worldAddress: Address) { const client = await getClient(chainId); const toBlock = await getBlockNumber(client); const logs = await getLogs(client, { @@ -39,6 +37,7 @@ export async function GET(req: Request) { const { searchParams } = new URL(req.url); const worldAddress = searchParams.get("worldAddress") as Hex; const chainId = Number(searchParams.get("chainId")); + isValidChainId(chainId); if (!worldAddress) { return Response.json({ error: "address is required" }, { status: 400 }); From fafc6d4846cecd35d909d5cba4c4defafa84f826 Mon Sep 17 00:00:00 2001 From: karooolis Date: Mon, 16 Sep 2024 14:53:33 +0300 Subject: [PATCH 17/27] memoize wagmi config --- .../src/app/[chainName]/Providers.tsx | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/packages/explorer/src/app/[chainName]/Providers.tsx b/packages/explorer/src/app/[chainName]/Providers.tsx index 5c90007d16..bdba1d1531 100644 --- a/packages/explorer/src/app/[chainName]/Providers.tsx +++ b/packages/explorer/src/app/[chainName]/Providers.tsx @@ -2,7 +2,7 @@ import { WagmiProvider, createConfig, http } from "wagmi"; import { injected, metaMask, safe } from "wagmi/connectors"; -import { ReactNode } from "react"; +import { ReactNode, useMemo } from "react"; import { RainbowKitProvider, darkTheme } from "@rainbow-me/rainbowkit"; import "@rainbow-me/rainbowkit/styles.css"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; @@ -13,23 +13,25 @@ const queryClient = new QueryClient(); export function Providers({ children }: { children: ReactNode }) { const chain = useChain(); - const wagmiConfig = createConfig({ - chains: [chain], - connectors: [ - injected(), - metaMask({ - dappMetadata: { - name: "World Explorer", - }, - }), - safe(), - ...getDefaultAnvilConnectors(chain.id), - ], - transports: { - [chain.id]: http(), - }, - ssr: true, - }); + const wagmiConfig = useMemo(() => { + return createConfig({ + chains: [chain], + connectors: [ + injected(), + metaMask({ + dappMetadata: { + name: "World Explorer", + }, + }), + safe(), + ...getDefaultAnvilConnectors(chain.id), + ], + transports: { + [chain.id]: http(), + }, + ssr: true, + }); + }, [chain]); return ( From 99c20691835ba8e780affb708951b071e522a47a Mon Sep 17 00:00:00 2001 From: karooolis Date: Mon, 16 Sep 2024 15:02:11 +0300 Subject: [PATCH 18/27] move provider, remove redundant layout --- .../{ => (explorer)/worlds/[worldAddress]}/Providers.tsx | 4 ++-- .../(explorer)/worlds/[worldAddress]/layout.tsx | 5 +++-- packages/explorer/src/app/[chainName]/layout.tsx | 9 --------- 3 files changed, 5 insertions(+), 13 deletions(-) rename packages/explorer/src/app/[chainName]/{ => (explorer)/worlds/[worldAddress]}/Providers.tsx (89%) delete mode 100644 packages/explorer/src/app/[chainName]/layout.tsx diff --git a/packages/explorer/src/app/[chainName]/Providers.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/Providers.tsx similarity index 89% rename from packages/explorer/src/app/[chainName]/Providers.tsx rename to packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/Providers.tsx index bdba1d1531..c1d4a45e8d 100644 --- a/packages/explorer/src/app/[chainName]/Providers.tsx +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/Providers.tsx @@ -6,8 +6,8 @@ import { ReactNode, useMemo } from "react"; import { RainbowKitProvider, darkTheme } from "@rainbow-me/rainbowkit"; import "@rainbow-me/rainbowkit/styles.css"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; -import { getDefaultAnvilConnectors } from "../../connectors/anvil"; -import { useChain } from "../../hooks/useChain"; +import { getDefaultAnvilConnectors } from "../../../../../connectors/anvil"; +import { useChain } from "../../../../../hooks/useChain"; const queryClient = new QueryClient(); diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/layout.tsx b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/layout.tsx index 41d7d524bf..5b4c354560 100644 --- a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/layout.tsx +++ b/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/layout.tsx @@ -1,12 +1,13 @@ "use client"; import { Navigation } from "../../../../../components/Navigation"; +import { Providers } from "./Providers"; export default function WorldLayout({ children }: { children: React.ReactNode }) { return ( -
+ {children} -
+ ); } diff --git a/packages/explorer/src/app/[chainName]/layout.tsx b/packages/explorer/src/app/[chainName]/layout.tsx deleted file mode 100644 index 46f7c14b27..0000000000 --- a/packages/explorer/src/app/[chainName]/layout.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { Providers } from "./Providers"; - -export default function WorldsLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - return {children}; -} From 748929e22a1d91c06cf2644c13b4b51bbf7aa877 Mon Sep 17 00:00:00 2001 From: karooolis Date: Mon, 16 Sep 2024 15:07:17 +0300 Subject: [PATCH 19/27] cleanup --- packages/explorer/src/components/ConnectButton.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/explorer/src/components/ConnectButton.tsx b/packages/explorer/src/components/ConnectButton.tsx index b274063de0..b1abfce226 100644 --- a/packages/explorer/src/components/ConnectButton.tsx +++ b/packages/explorer/src/components/ConnectButton.tsx @@ -12,7 +12,6 @@ export function ConnectButton() { {({ account, chain, openAccountModal, openChainModal, openConnectModal, mounted }) => { const connected = mounted && account && chain; - return (
Date: Mon, 16 Sep 2024 16:27:32 +0300 Subject: [PATCH 20/27] explicitly add favicon --- packages/explorer/{src/app/icon.svg => public/favicon.svg} | 0 packages/explorer/src/app/layout.tsx | 3 +++ 2 files changed, 3 insertions(+) rename packages/explorer/{src/app/icon.svg => public/favicon.svg} (100%) diff --git a/packages/explorer/src/app/icon.svg b/packages/explorer/public/favicon.svg similarity index 100% rename from packages/explorer/src/app/icon.svg rename to packages/explorer/public/favicon.svg diff --git a/packages/explorer/src/app/layout.tsx b/packages/explorer/src/app/layout.tsx index 533d78abcf..1dd8395953 100644 --- a/packages/explorer/src/app/layout.tsx +++ b/packages/explorer/src/app/layout.tsx @@ -19,6 +19,9 @@ const jetbrains = JetBrains_Mono({ export const metadata: Metadata = { title: "World Explorer", description: "World Explorer is a tool for visually exploring and manipulating the state of worlds", + icons: { + icon: "/favicon.svg", + }, }; export default function RootLayout({ From 7b4575bc6a2f00e13d888b1e4f00eadbe55ae44c Mon Sep 17 00:00:00 2001 From: karooolis Date: Tue, 17 Sep 2024 17:19:09 +0300 Subject: [PATCH 21/27] move chainName into explorer, modify supported chains --- .../app/{ => (explorer)}/[chainName]/page.tsx | 0 .../worlds/[worldAddress]/Providers.tsx | 0 .../[worldAddress]/explore/DataExplorer.tsx | 0 .../explore/EditableTableCell.tsx | 4 +- .../[worldAddress]/explore/TableSelector.tsx | 0 .../[worldAddress]/explore/TablesViewer.tsx | 0 .../worlds/[worldAddress]/explore/page.tsx | 0 .../worlds/[worldAddress]/interact/Form.tsx | 0 .../[worldAddress]/interact/FunctionField.tsx | 0 .../worlds/[worldAddress]/interact/page.tsx | 0 .../interact/useContractMutation.ts | 4 +- .../worlds/[worldAddress]/layout.tsx | 0 .../worlds/[worldAddress]/observe/Write.tsx | 0 .../worlds/[worldAddress]/observe/Writes.tsx | 0 .../worlds/[worldAddress]/observe/common.ts | 0 .../worlds/[worldAddress]/observe/page.tsx | 0 .../worlds/[worldAddress]/page.tsx | 0 .../[worldAddress]/utils/bufferToBigInt.ts | 0 .../[chainName]}/worlds/page.tsx | 0 packages/explorer/src/app/api/world/route.ts | 4 +- packages/explorer/src/app/page.tsx | 6 +-- packages/explorer/src/bin/explorer.ts | 4 +- packages/explorer/src/common.ts | 41 ++++++------------- .../explorer/src/components/ConnectButton.tsx | 4 +- packages/explorer/src/hooks/useChain.ts | 12 ++---- packages/explorer/src/queries/useAbiQuery.ts | 4 +- 26 files changed, 31 insertions(+), 52 deletions(-) rename packages/explorer/src/app/{ => (explorer)}/[chainName]/page.tsx (100%) rename packages/explorer/src/app/{[chainName]/(explorer) => (explorer)/[chainName]}/worlds/[worldAddress]/Providers.tsx (100%) rename packages/explorer/src/app/{[chainName]/(explorer) => (explorer)/[chainName]}/worlds/[worldAddress]/explore/DataExplorer.tsx (100%) rename packages/explorer/src/app/{[chainName]/(explorer) => (explorer)/[chainName]}/worlds/[worldAddress]/explore/EditableTableCell.tsx (97%) rename packages/explorer/src/app/{[chainName]/(explorer) => (explorer)/[chainName]}/worlds/[worldAddress]/explore/TableSelector.tsx (100%) rename packages/explorer/src/app/{[chainName]/(explorer) => (explorer)/[chainName]}/worlds/[worldAddress]/explore/TablesViewer.tsx (100%) rename packages/explorer/src/app/{[chainName]/(explorer) => (explorer)/[chainName]}/worlds/[worldAddress]/explore/page.tsx (100%) rename packages/explorer/src/app/{[chainName]/(explorer) => (explorer)/[chainName]}/worlds/[worldAddress]/interact/Form.tsx (100%) rename packages/explorer/src/app/{[chainName]/(explorer) => (explorer)/[chainName]}/worlds/[worldAddress]/interact/FunctionField.tsx (100%) rename packages/explorer/src/app/{[chainName]/(explorer) => (explorer)/[chainName]}/worlds/[worldAddress]/interact/page.tsx (100%) rename packages/explorer/src/app/{[chainName]/(explorer) => (explorer)/[chainName]}/worlds/[worldAddress]/interact/useContractMutation.ts (96%) rename packages/explorer/src/app/{[chainName]/(explorer) => (explorer)/[chainName]}/worlds/[worldAddress]/layout.tsx (100%) rename packages/explorer/src/app/{[chainName]/(explorer) => (explorer)/[chainName]}/worlds/[worldAddress]/observe/Write.tsx (100%) rename packages/explorer/src/app/{[chainName]/(explorer) => (explorer)/[chainName]}/worlds/[worldAddress]/observe/Writes.tsx (100%) rename packages/explorer/src/app/{[chainName]/(explorer) => (explorer)/[chainName]}/worlds/[worldAddress]/observe/common.ts (100%) rename packages/explorer/src/app/{[chainName]/(explorer) => (explorer)/[chainName]}/worlds/[worldAddress]/observe/page.tsx (100%) rename packages/explorer/src/app/{[chainName]/(explorer) => (explorer)/[chainName]}/worlds/[worldAddress]/page.tsx (100%) rename packages/explorer/src/app/{[chainName]/(explorer) => (explorer)/[chainName]}/worlds/[worldAddress]/utils/bufferToBigInt.ts (100%) rename packages/explorer/src/app/{[chainName]/(explorer) => (explorer)/[chainName]}/worlds/page.tsx (100%) diff --git a/packages/explorer/src/app/[chainName]/page.tsx b/packages/explorer/src/app/(explorer)/[chainName]/page.tsx similarity index 100% rename from packages/explorer/src/app/[chainName]/page.tsx rename to packages/explorer/src/app/(explorer)/[chainName]/page.tsx diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/Providers.tsx b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/Providers.tsx similarity index 100% rename from packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/Providers.tsx rename to packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/Providers.tsx diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/DataExplorer.tsx b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/DataExplorer.tsx similarity index 100% rename from packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/DataExplorer.tsx rename to packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/DataExplorer.tsx diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/EditableTableCell.tsx similarity index 97% rename from packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx rename to packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/EditableTableCell.tsx index 259f1dcd0c..51839a1ad3 100644 --- a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/EditableTableCell.tsx +++ b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/EditableTableCell.tsx @@ -10,7 +10,7 @@ import IBaseWorldAbi from "@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.j import { useMutation, useQueryClient } from "@tanstack/react-query"; import { waitForTransactionReceipt, writeContract } from "@wagmi/core"; import { Checkbox } from "../../../../../../components/ui/Checkbox"; -import { useChainId } from "../../../../../../hooks/useChain"; +import { useChain } from "../../../../../../hooks/useChain"; import { camelCase, cn } from "../../../../../../lib/utils"; import { TableConfig } from "../../../../../api/table/route"; @@ -25,7 +25,7 @@ export function EditableTableCell({ name, config, keyTuple, value: defaultValue const wagmiConfig = useConfig(); const queryClient = useQueryClient(); const { worldAddress } = useParams(); - const chainId = useChainId(); + const { id: chainId } = useChain(); const account = useAccount(); const [value, setValue] = useState(defaultValue); diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/TableSelector.tsx b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/TableSelector.tsx similarity index 100% rename from packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/TableSelector.tsx rename to packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/TableSelector.tsx diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/TablesViewer.tsx b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/TablesViewer.tsx similarity index 100% rename from packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/TablesViewer.tsx rename to packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/TablesViewer.tsx diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/page.tsx b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/page.tsx similarity index 100% rename from packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/explore/page.tsx rename to packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/explore/page.tsx diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/Form.tsx b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/interact/Form.tsx similarity index 100% rename from packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/Form.tsx rename to packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/interact/Form.tsx diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/FunctionField.tsx b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/interact/FunctionField.tsx similarity index 100% rename from packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/FunctionField.tsx rename to packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/interact/FunctionField.tsx diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/page.tsx b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/interact/page.tsx similarity index 100% rename from packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/page.tsx rename to packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/interact/page.tsx diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/interact/useContractMutation.ts similarity index 96% rename from packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts rename to packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/interact/useContractMutation.ts index 4ece341f70..50e02e7b06 100644 --- a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/interact/useContractMutation.ts +++ b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/interact/useContractMutation.ts @@ -4,7 +4,7 @@ import { Abi, AbiFunction, Hex } from "viem"; import { useAccount, useConfig } from "wagmi"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { readContract, waitForTransactionReceipt, writeContract } from "@wagmi/core"; -import { useChainId } from "../../../../../../hooks/useChain"; +import { useChain } from "../../../../../../hooks/useChain"; import { FunctionType } from "./FunctionField"; type UseContractMutationProps = { @@ -14,7 +14,7 @@ type UseContractMutationProps = { export function useContractMutation({ abi, operationType }: UseContractMutationProps) { const { worldAddress } = useParams(); - const chainId = useChainId(); + const { id: chainId } = useChain(); const queryClient = useQueryClient(); const wagmiConfig = useConfig(); const account = useAccount(); diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/layout.tsx b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/layout.tsx similarity index 100% rename from packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/layout.tsx rename to packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/layout.tsx diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/observe/Write.tsx b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/observe/Write.tsx similarity index 100% rename from packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/observe/Write.tsx rename to packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/observe/Write.tsx diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/observe/Writes.tsx b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/observe/Writes.tsx similarity index 100% rename from packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/observe/Writes.tsx rename to packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/observe/Writes.tsx diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/observe/common.ts b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/observe/common.ts similarity index 100% rename from packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/observe/common.ts rename to packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/observe/common.ts diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/observe/page.tsx b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/observe/page.tsx similarity index 100% rename from packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/observe/page.tsx rename to packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/observe/page.tsx diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/page.tsx b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/page.tsx similarity index 100% rename from packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/page.tsx rename to packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/page.tsx diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/utils/bufferToBigInt.ts b/packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/utils/bufferToBigInt.ts similarity index 100% rename from packages/explorer/src/app/[chainName]/(explorer)/worlds/[worldAddress]/utils/bufferToBigInt.ts rename to packages/explorer/src/app/(explorer)/[chainName]/worlds/[worldAddress]/utils/bufferToBigInt.ts diff --git a/packages/explorer/src/app/[chainName]/(explorer)/worlds/page.tsx b/packages/explorer/src/app/(explorer)/[chainName]/worlds/page.tsx similarity index 100% rename from packages/explorer/src/app/[chainName]/(explorer)/worlds/page.tsx rename to packages/explorer/src/app/(explorer)/[chainName]/worlds/page.tsx diff --git a/packages/explorer/src/app/api/world/route.ts b/packages/explorer/src/app/api/world/route.ts index e399362663..50a4652343 100644 --- a/packages/explorer/src/app/api/world/route.ts +++ b/packages/explorer/src/app/api/world/route.ts @@ -3,7 +3,7 @@ import { getBlockNumber, getLogs } from "viem/actions"; import { helloStoreEvent } from "@latticexyz/store"; import { helloWorldEvent } from "@latticexyz/world"; import { getWorldAbi } from "@latticexyz/world/internal"; -import { SupportedChainIds, chains, isValidChainId } from "../../../common"; +import { SupportedChainIds, chains, validateChainId } from "../../../common"; export const dynamic = "force-dynamic"; @@ -37,7 +37,7 @@ export async function GET(req: Request) { const { searchParams } = new URL(req.url); const worldAddress = searchParams.get("worldAddress") as Hex; const chainId = Number(searchParams.get("chainId")); - isValidChainId(chainId); + validateChainId(chainId); if (!worldAddress) { return Response.json({ error: "address is required" }, { status: 400 }); diff --git a/packages/explorer/src/app/page.tsx b/packages/explorer/src/app/page.tsx index e477f1caea..cfa56011be 100644 --- a/packages/explorer/src/app/page.tsx +++ b/packages/explorer/src/app/page.tsx @@ -1,12 +1,12 @@ import { redirect } from "next/navigation"; -import { SupportedChainIds, chainIdName, isValidChainId } from "../common"; +import { supportedChainsById, validateChainId } from "../common"; export const dynamic = "force-dynamic"; export default function IndexPage() { const chainId = Number(process.env.CHAIN_ID); - isValidChainId(chainId); + validateChainId(chainId); - const chainName = chainIdName[chainId as SupportedChainIds]; + const chainName = supportedChainsById[chainId]; return redirect(`/${chainName}/worlds`); } diff --git a/packages/explorer/src/bin/explorer.ts b/packages/explorer/src/bin/explorer.ts index 15c996b19f..6e5c551162 100755 --- a/packages/explorer/src/bin/explorer.ts +++ b/packages/explorer/src/bin/explorer.ts @@ -6,7 +6,7 @@ import process from "process"; import { fileURLToPath } from "url"; import yargs from "yargs"; import { ChildProcess, spawn } from "child_process"; -import { isValidChainId } from "../common"; +import { validateChainId } from "../common"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -57,7 +57,7 @@ const argv = yargs(process.argv.slice(2)) }, }) .check((argv) => { - isValidChainId(Number(argv.chainId)); + validateChainId(Number(argv.chainId)); return true; }) .parseSync(); diff --git a/packages/explorer/src/common.ts b/packages/explorer/src/common.ts index 5e47d81ab2..5b538ac063 100644 --- a/packages/explorer/src/common.ts +++ b/packages/explorer/src/common.ts @@ -1,36 +1,21 @@ -import { Chain, anvil, garnet, redstone } from "viem/chains"; +import { anvil, garnet, redstone } from "viem/chains"; -const supportedChains = [anvil, garnet, redstone]; +export const supportedChains = { anvil, garnet, redstone } as const; +export const supportedChainsById = Object.fromEntries( + Object.entries(supportedChains).map(([name, chain]) => [chain.id, name]), +); -export type SupportedChainIds = (typeof supportedChains)[number]["id"]; -export type SupportedChainNames = "anvil" | "garnet" | "redstone"; +export type SupportedChainIds = (typeof supportedChains)[keyof typeof supportedChains]["id"]; +export type SupportedChainNames = keyof typeof supportedChains; -export const chainIdName: Record = { - [anvil.id]: "anvil", - [garnet.id]: "garnet", - [redstone.id]: "redstone", -} as const; - -export const chainNameId: Record = { - anvil: anvil.id, - garnet: garnet.id, - redstone: redstone.id, -}; - -export const chains: Record = { - [anvil.id]: anvil, - [garnet.id]: garnet, - [redstone.id]: redstone, -}; - -export function isValidChainId(chainId: number): asserts chainId is SupportedChainIds { - if (!(chainId in chainIdName)) { - throw new Error(`Invalid chain id. Supported chains are: ${Object.keys(chainIdName).join(", ")}.`); +export function validateChainId(chainId: number): asserts chainId is SupportedChainIds { + if (!(chainId in supportedChainsById)) { + throw new Error(`Invalid chain id. Supported chains are: ${Object.keys(supportedChainsById).join(", ")}.`); } } -export function isValidChainName(name: string | string[] | undefined): asserts name is SupportedChainNames { - if (Array.isArray(name) || typeof name !== "string" || !(name in chainNameId)) { - throw new Error(`Invalid chain name. Supported chains are: ${Object.keys(chainNameId).join(", ")}.`); +export function validateChainName(name: string | string[] | undefined): asserts name is SupportedChainNames { + if (Array.isArray(name) || typeof name !== "string" || !(name in supportedChains)) { + throw new Error(`Invalid chain name. Supported chains are: ${Object.keys(supportedChainsById).join(", ")}.`); } } diff --git a/packages/explorer/src/components/ConnectButton.tsx b/packages/explorer/src/components/ConnectButton.tsx index b1abfce226..e2831d8343 100644 --- a/packages/explorer/src/components/ConnectButton.tsx +++ b/packages/explorer/src/components/ConnectButton.tsx @@ -1,13 +1,13 @@ import { PlugIcon, ZapIcon } from "lucide-react"; import { anvil } from "viem/chains"; import { ConnectButton as RainbowConnectButton } from "@rainbow-me/rainbowkit"; -import { useChainId } from "../hooks/useChain"; +import { useChain } from "../hooks/useChain"; import { cn } from "../lib/utils"; import { AccountSelect } from "./AccountSelect"; import { Button } from "./ui/Button"; export function ConnectButton() { - const chainId = useChainId(); + const { id: chainId } = useChain(); return ( {({ account, chain, openAccountModal, openChainModal, openConnectModal, mounted }) => { diff --git a/packages/explorer/src/hooks/useChain.ts b/packages/explorer/src/hooks/useChain.ts index a36f628e27..8a8f077fc6 100644 --- a/packages/explorer/src/hooks/useChain.ts +++ b/packages/explorer/src/hooks/useChain.ts @@ -1,16 +1,10 @@ import { useParams } from "next/navigation"; -import { chainNameId, chains, isValidChainName } from "../common"; +import { supportedChains, validateChainName } from "../common"; export function useChain() { const { chainName } = useParams(); - isValidChainName(chainName); + validateChainName(chainName); - const chainId = chainNameId[chainName]; - const chain = chains[chainId]; + const chain = supportedChains[chainName]; return chain; } - -export function useChainId() { - const chain = useChain(); - return chain.id; -} diff --git a/packages/explorer/src/queries/useAbiQuery.ts b/packages/explorer/src/queries/useAbiQuery.ts index b474efcf7c..db8bed764b 100644 --- a/packages/explorer/src/queries/useAbiQuery.ts +++ b/packages/explorer/src/queries/useAbiQuery.ts @@ -1,7 +1,7 @@ import { useParams } from "next/navigation"; import { AbiFunction, Hex } from "viem"; import { UseQueryResult, useQuery } from "@tanstack/react-query"; -import { useChainId } from "../hooks/useChain"; +import { useChain } from "../hooks/useChain"; export async function getAbi(chainId: number, worldAddress: Hex) { const res = await fetch(`/api/world?${new URLSearchParams({ chainId: String(chainId), worldAddress })}`); @@ -20,7 +20,7 @@ type AbiQueryResult = { export const useAbiQuery = (): UseQueryResult => { const { worldAddress } = useParams(); - const chainId = useChainId(); + const { id: chainId } = useChain(); return useQuery({ queryKey: ["abi", chainId, worldAddress], From c01e7436147020bfda37298ef76584720bf8eb4a Mon Sep 17 00:00:00 2001 From: karooolis Date: Tue, 17 Sep 2024 17:25:11 +0300 Subject: [PATCH 22/27] get correct chain in world route --- packages/explorer/src/app/api/world/route.ts | 5 +++-- packages/explorer/src/common.ts | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/explorer/src/app/api/world/route.ts b/packages/explorer/src/app/api/world/route.ts index 50a4652343..650dee9bad 100644 --- a/packages/explorer/src/app/api/world/route.ts +++ b/packages/explorer/src/app/api/world/route.ts @@ -3,13 +3,14 @@ import { getBlockNumber, getLogs } from "viem/actions"; import { helloStoreEvent } from "@latticexyz/store"; import { helloWorldEvent } from "@latticexyz/world"; import { getWorldAbi } from "@latticexyz/world/internal"; -import { SupportedChainIds, chains, validateChainId } from "../../../common"; +import { SupportedChainIds, supportedChainsById, validateChainId } from "../../../common"; export const dynamic = "force-dynamic"; async function getClient(chainId: SupportedChainIds) { + const chain = supportedChainsById[chainId]; const client = createWalletClient({ - chain: chains[chainId], + chain, transport: http(), }); diff --git a/packages/explorer/src/common.ts b/packages/explorer/src/common.ts index 5b538ac063..de77ede488 100644 --- a/packages/explorer/src/common.ts +++ b/packages/explorer/src/common.ts @@ -2,7 +2,7 @@ import { anvil, garnet, redstone } from "viem/chains"; export const supportedChains = { anvil, garnet, redstone } as const; export const supportedChainsById = Object.fromEntries( - Object.entries(supportedChains).map(([name, chain]) => [chain.id, name]), + Object.entries(supportedChains).map(([, chain]) => [chain.id, chain]), ); export type SupportedChainIds = (typeof supportedChains)[keyof typeof supportedChains]["id"]; From 90ab8186302489f22589b629233287488b766451 Mon Sep 17 00:00:00 2001 From: karooolis Date: Tue, 17 Sep 2024 17:30:46 +0300 Subject: [PATCH 23/27] add favicon crisp --- packages/explorer/public/favicon.svg | 2 +- packages/explorer/src/hooks/useChain.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/explorer/public/favicon.svg b/packages/explorer/public/favicon.svg index 55f3761258..bd1b31a197 100644 --- a/packages/explorer/public/favicon.svg +++ b/packages/explorer/public/favicon.svg @@ -1,4 +1,4 @@ - + diff --git a/packages/explorer/src/hooks/useChain.ts b/packages/explorer/src/hooks/useChain.ts index 8a8f077fc6..31556bda55 100644 --- a/packages/explorer/src/hooks/useChain.ts +++ b/packages/explorer/src/hooks/useChain.ts @@ -1,7 +1,8 @@ import { useParams } from "next/navigation"; +import { Chain } from "viem"; import { supportedChains, validateChainName } from "../common"; -export function useChain() { +export function useChain(): Chain { const { chainName } = useParams(); validateChainName(chainName); From b527702f06278ee20899421522cabb2e0440f2ea Mon Sep 17 00:00:00 2001 From: karooolis Date: Tue, 17 Sep 2024 17:37:02 +0300 Subject: [PATCH 24/27] update favicon --- packages/explorer/public/favicon.svg | 95 +++++++++++++--------------- 1 file changed, 45 insertions(+), 50 deletions(-) diff --git a/packages/explorer/public/favicon.svg b/packages/explorer/public/favicon.svg index bd1b31a197..37698f3287 100644 --- a/packages/explorer/public/favicon.svg +++ b/packages/explorer/public/favicon.svg @@ -1,55 +1,50 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + From 07b1af32785ba33e0b732cafded0fe02e1f54d80 Mon Sep 17 00:00:00 2001 From: karooolis Date: Tue, 17 Sep 2024 21:18:14 +0300 Subject: [PATCH 25/27] add explorer to explore redirect --- packages/explorer/next.config.mjs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/explorer/next.config.mjs b/packages/explorer/next.config.mjs index 6eab04cefe..2969929ed5 100644 --- a/packages/explorer/next.config.mjs +++ b/packages/explorer/next.config.mjs @@ -8,6 +8,15 @@ export default function config() { config.externals.push("pino-pretty", "lokijs", "encoding"); return config; }, + redirects: async () => { + return [ + { + source: "/:chainName/worlds/:worldAddress/explorer", + destination: "/:chainName/worlds/:worldAddress/explorer", + permanent: true, + }, + ]; + }, }; return nextConfig; From f25d4f2e19af8151e2bc7fd5c190304b475632e5 Mon Sep 17 00:00:00 2001 From: Karolis Ramanauskas Date: Tue, 17 Sep 2024 21:28:03 +0300 Subject: [PATCH 26/27] Create perfect-plants-hang.md --- .changeset/perfect-plants-hang.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/perfect-plants-hang.md diff --git a/.changeset/perfect-plants-hang.md b/.changeset/perfect-plants-hang.md new file mode 100644 index 0000000000..1a74d6c439 --- /dev/null +++ b/.changeset/perfect-plants-hang.md @@ -0,0 +1,5 @@ +--- +"@latticexyz/explorer": patch +--- + +Added ability to connect World Explorer to Redstone and Garnet chains. The active chain is now passed as a dynamic route parameter. From 8a925625c5e427d96986a09680fc5be7b8f328a8 Mon Sep 17 00:00:00 2001 From: karooolis Date: Tue, 17 Sep 2024 21:39:55 +0300 Subject: [PATCH 27/27] correct redirect url --- packages/explorer/next.config.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/explorer/next.config.mjs b/packages/explorer/next.config.mjs index 2969929ed5..cffb1b98ba 100644 --- a/packages/explorer/next.config.mjs +++ b/packages/explorer/next.config.mjs @@ -12,7 +12,7 @@ export default function config() { return [ { source: "/:chainName/worlds/:worldAddress/explorer", - destination: "/:chainName/worlds/:worldAddress/explorer", + destination: "/:chainName/worlds/:worldAddress/explore", permanent: true, }, ];