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" && (