diff --git a/.env.example b/.env.example index bc6a8b025..7f7285244 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,7 @@ # --------------------------------- REQUIRED --------------------------------- # # The identifier of the chain the client is running on # e.g. "dev" for the anvil node, or any chain the game is deployed on, with some config specified in `packages/core/src/network/config/chainConfigs.ts` -PRI_CHAIN_ID="dev" +PRI_CHAIN_ID=216 # This will grant access to the Game Tools browser (for the editor and cheat codes) and Mud Dev Tools PRI_DEV="true" diff --git a/packages/client/package.json b/packages/client/package.json index 990b81841..9e6c42afd 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -21,6 +21,8 @@ "@amplitude/analytics-browser": "^2.1.3", "@fontsource/silkscreen": "^5.0.18", "@fontsource/space-mono": "^5.0.14", + "@happy.tech/core": "^0.2.1", + "@happy.tech/react": "^0.2.1", "@latticexyz/common": "2.0.9", "@latticexyz/faucet": "2.0.9", "@latticexyz/protocol-parser": "2.0.9", diff --git a/packages/client/public/img/icons/web3/happychain.png b/packages/client/public/img/icons/web3/happychain.png new file mode 100644 index 000000000..4c089cf29 Binary files /dev/null and b/packages/client/public/img/icons/web3/happychain.png differ diff --git a/packages/client/src/AppLoadingState.tsx b/packages/client/src/AppLoadingState.tsx index 1e1574110..b07bdb3f5 100644 --- a/packages/client/src/AppLoadingState.tsx +++ b/packages/client/src/AppLoadingState.tsx @@ -1,5 +1,6 @@ import { useEffect, useMemo } from "react"; import { BrowserRouter, Navigate, Route, Routes, useLocation } from "react-router-dom"; +import { toast } from "react-toastify"; import { minEth } from "@primodiumxyz/core"; import { useAccountClient, useSyncStatus } from "@primodiumxyz/core/react"; @@ -13,42 +14,23 @@ import { Sandbox } from "@/screens/Sandbox"; import { Statistics } from "@/screens/Statistics"; export default function AppLoadingState() { - const { playerBalanceData, sessionBalanceData, requestDrip } = useDripAccount(); + const { playerBalanceData, sessionBalanceData } = useDripAccount(); const { sessionAccount, playerAccount } = useAccountClient(); - - useEffect(() => { - const sessionBalance = sessionBalanceData.data?.value; - if (!sessionAccount?.address || sessionBalanceData.isLoading || !sessionBalance || sessionBalance >= minEth) return; - console.log("dripping session account"); - requestDrip(sessionAccount.address); - }, [sessionAccount?.address, sessionBalanceData.data?.value, sessionBalanceData.isLoading]); - - useEffect(() => { - const playerBalance = playerBalanceData.data?.value; - if (sessionBalanceData.isLoading || !playerBalance || playerBalance >= minEth) return; - console.log("dripping player account"); - requestDrip(playerAccount.address); - }, [playerAccount.address, sessionBalanceData.isLoading, playerBalanceData.data?.value]); - const { loading, error, progress, message } = useSyncStatus(playerAccount.entity); const balanceReady = useMemo(() => { const playerBalanceReady = (playerBalanceData.data?.value ?? 0n) >= minEth; const sessionBalanceReady = !sessionAccount || (sessionBalanceData.data?.value ?? 0n) >= minEth; return playerBalanceReady && sessionBalanceReady; }, [loading, playerBalanceData, sessionAccount, sessionBalanceData]); + + useEffect(() => { + if (!balanceReady) toast.warn("Please top up your $HAPPY balance."); + }, [balanceReady]); + return (
{!error && (
- {!loading && !balanceReady && ( -
-

- Dripping Eth to Primodium account - -

- -
- )} {loading && (
@@ -68,7 +50,7 @@ export default function AppLoadingState() {
)} - {!loading && balanceReady && ( + {!loading && ( diff --git a/packages/client/src/Connect.tsx b/packages/client/src/Connect.tsx index 5d0c60bd9..aedd1f18c 100644 --- a/packages/client/src/Connect.tsx +++ b/packages/client/src/Connect.tsx @@ -1,86 +1,28 @@ import { chunk } from "lodash"; -import React, { useEffect, useState } from "react"; -import { FaExclamationTriangle } from "react-icons/fa"; +import React, { useEffect } from "react"; import { toast } from "react-toastify"; import { useAccount, useConnect } from "wagmi"; -import { usePersistentStore } from "@primodiumxyz/game/src/stores/PersistentStore"; import { Landing } from "@/screens/Landing"; const connectorIcons: Record = { - ["MetaMask"]: "/img/icons/web3/metamask.svg", - ["WalletConnect"]: "/img/icons/web3/walletconnect.svg", - ["Coinbase Wallet"]: "/img/icons/web3/coinbase.svg", + ["HappyChain Wagmi Provider"]: "/img/icons/web3/happychain.png", // [HAPPY_PRIM] new icon, provided name is configured within the package }; +/** [HAPPY_PRIM] We only show the happychain connector here since we want them to play using the HappyWallet! */ export const Connect: React.FC = React.memo(() => { const { connector, isConnected } = useAccount(); const { connect, connectors, error, isPending } = useConnect(); - const { noExternalAccount, setNoExternalAccount } = usePersistentStore(); - const [showingToast, setShowingToast] = useState(false); useEffect(() => { if (error) toast.warn(error.message); }, [error]); - const confirmToast = async () => { - toast.dismiss(); - if (showingToast) await new Promise((resolve) => setTimeout(resolve, 500)); - setShowingToast(true); - toast( - ({ closeToast }) => ( -
-
- - Are you sure you want to login as guest? You will not be able to win prizes or play across devices. -
- -
- - -
-
- ), - { - // className: "border-error", - position: "top-center", - autoClose: false, - closeOnClick: false, - draggable: false, - closeButton: false, - hideProgressBar: true, - }, - ); - }; - - if (isConnected || noExternalAccount) return null; + if (isConnected) return null; return (
- - {chunk( connectors.filter((x) => x.id !== connector?.id), 2, diff --git a/packages/client/src/components/hud/command/transfer/TransferSelect.tsx b/packages/client/src/components/hud/command/transfer/TransferSelect.tsx index 19a9a9a05..2e2313bca 100644 --- a/packages/client/src/components/hud/command/transfer/TransferSelect.tsx +++ b/packages/client/src/components/hud/command/transfer/TransferSelect.tsx @@ -74,7 +74,7 @@ export const TransferSelect = ({ side }: { side: "left" | "right" }) => { ))}
{showNewFleet && ( -
+
{!canBuildFleet && (

Reached Max Fleet Count. Build a Starmapper Station to build more fleets. diff --git a/packages/client/src/config/getCoreConfig.ts b/packages/client/src/config/getCoreConfig.ts index 5867690e3..ce2c2ab00 100644 --- a/packages/client/src/config/getCoreConfig.ts +++ b/packages/client/src/config/getCoreConfig.ts @@ -1,19 +1,28 @@ import worldsJson from "contracts/worlds.json"; import { Address, Hex } from "viem"; -import { chainConfigs, CoreConfig } from "@primodiumxyz/core"; +import { ChainConfig, chainConfigs, CoreConfig } from "@primodiumxyz/core"; const worlds = worldsJson as Partial>; +const findChainById = (id: number | string): ChainConfig => { + const chain = Object.values(chainConfigs).find((chain) => chain.id === Number(id)); + if (!chain) { + throw new Error(`No chain found with ID ${id}`); + } + return chain; +}; + export const getCoreConfig = (): CoreConfig => { // Ignore deployment URL params on production subdomains (primodium.com) const params = window.location.hostname.endsWith("primodium.com") ? new URLSearchParams() : new URLSearchParams(window.location.search); - const chainId = (params.get("chainid") || import.meta.env.PRI_CHAIN_ID || "dev") as keyof typeof chainConfigs; + const chainId = params.get("chainid") || import.meta.env.PRI_CHAIN_ID || "dev"; + const chain = findChainById(chainId); - const chain = chainConfigs[chainId]; + console.log(chain); const world = worlds[chain.id]; const worldAddress = (params.get("worldAddress") || world?.address) as Address; diff --git a/packages/client/src/config/wagmiConfig.ts b/packages/client/src/config/wagmiConfig.ts index 7088b9095..6d3ec2c50 100644 --- a/packages/client/src/config/wagmiConfig.ts +++ b/packages/client/src/config/wagmiConfig.ts @@ -1,23 +1,5 @@ -import { createClient } from "viem"; -import { createConfig, http } from "wagmi"; -import { coinbaseWallet, walletConnect } from "wagmi/connectors"; +import { createHappyChainWagmiConfig, happyChainSepolia } from "@happy.tech/core"; +import { Config } from "wagmi"; -import { getCoreConfig } from "@/config/getCoreConfig"; - -const env = import.meta.env; -const projectId = env.PRI_WALLETCONNECT_PROJECT_ID; - -const { chain } = getCoreConfig(); - -export const wagmiConfig = createConfig({ - chains: [chain], - - client({ chain }) { - return createClient({ chain, transport: http() }); - }, - connectors: [ - walletConnect({ projectId }), - coinbaseWallet({ appName: "wagmi" }), - // injected({target: 'Injected', shimDisconnect: true}), - ], -}); +// [HAPPY_PRIM] use custom config tailored to HappyChain +export const wagmiConfig: Config = createHappyChainWagmiConfig(happyChainSepolia); diff --git a/packages/client/src/index.tsx b/packages/client/src/index.tsx index c93f96049..6c22617cf 100644 --- a/packages/client/src/index.tsx +++ b/packages/client/src/index.tsx @@ -1,3 +1,4 @@ +import { HappyWalletProvider } from "@happy.tech/react"; import { Analytics } from "@vercel/analytics/react"; import ReactDOM from "react-dom/client"; @@ -9,9 +10,12 @@ const rootElement = document.getElementById("react-root"); if (!rootElement) throw new Error("React root not found"); const root = ReactDOM.createRoot(rootElement); +// [HAPPY_PRIM] wrap app + inject wallet using the HProvider root.render( <> - - + + + + , ); diff --git a/packages/client/src/screens/Enter.tsx b/packages/client/src/screens/Enter.tsx index 0d1fb5ebb..59db0889d 100644 --- a/packages/client/src/screens/Enter.tsx +++ b/packages/client/src/screens/Enter.tsx @@ -104,7 +104,7 @@ export const Enter: React.FC = () => { return ( - + {state === "delegate" && (