diff --git a/packages/client/src/components/transfer/Authorize.tsx b/packages/client/src/components/transfer/Authorize.tsx
index 1707b943d..6973b6363 100644
--- a/packages/client/src/components/transfer/Authorize.tsx
+++ b/packages/client/src/components/transfer/Authorize.tsx
@@ -1,58 +1,36 @@
-import { useEffect, useState } from "react";
-import { FaClipboard, FaExclamationCircle, FaEye, FaEyeSlash, FaInfoCircle, FaTimes, FaUnlink } from "react-icons/fa";
-import { Address, Hex } from "viem";
-import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
+import { requestSessionKey } from "@happy.tech/core";
+import { useState } from "react";
+import { FaInfoCircle, FaTimes } from "react-icons/fa";
-import { STORAGE_PREFIX } from "@primodiumxyz/core";
import { useAccountClient } from "@primodiumxyz/core/react";
import { defaultEntity } from "@primodiumxyz/reactive-tables";
import { Button } from "@/components/core/Button";
import { SecondaryCard } from "@/components/core/Card";
import { TransactionQueueMask } from "@/components/shared/TransactionQueueMask";
-import { useContractCalls } from "@/hooks/useContractCalls";
-import { copyToClipboard } from "@/util/clipboard";
-import { findEntriesWithPrefix } from "@/util/localStorage";
+import { HAPPY_STORAGE_PREFIX, isHappySessionKeyRegistered } from "@/util/localStorage";
-const sessionWalletTooltip =
- "Bypass annoying confirmation popups by authorizing a session account. This allows you to securely perform certain actions without external confirmation.";
+const sessionWalletTooltip = (
+ <>
+ Bypass confirmation popups by authorizing a session key. Powered by{" "}
+ Happy Wallet , this lets you securely perform actions without repeated
+ approvals.
+ >
+);
export function Authorize() {
- const { sessionAccount } = useAccountClient();
- const { grantAccessWithSignature, revokeAccess } = useContractCalls();
- const [showDetails, setShowDetails] = useState(false);
+ const {
+ playerAccount: { address: playerAddress, worldContract },
+ } = useAccountClient();
const [showHelp, setShowHelp] = useState(!localStorage.getItem("hideHelp"));
- useEffect(() => {
- setShowDetails(false);
- }, [sessionAccount]);
+ const weAreHappySponsored = isHappySessionKeyRegistered(playerAddress);
- // Function to handle private key validation and connection
- const sessionAddress = sessionAccount?.address;
+ const handleHappySessionKeyRegister = async () => {
+ if (!isHappySessionKeyRegistered(playerAddress)) {
+ await requestSessionKey(worldContract.address);
- const submitPrivateKey = async (privateKey: Hex) => {
- // Validate the private key format here
- // This is a basic example, adjust the validation according to your requirements
- const isValid = /^0x[a-fA-F0-9]{64}$/.test(privateKey);
- if (!isValid) return;
- const account = privateKeyToAccount(privateKey as Hex);
-
- if (sessionAddress && sessionAddress === account.address) return;
- else await grantAccessWithSignature(privateKey, { id: defaultEntity });
- };
-
- const handleRandomPress = () => {
- const storedKeys = findEntriesWithPrefix();
- const privateKey = storedKeys.length > 0 ? storedKeys[0].privateKey : generatePrivateKey();
-
- const account = privateKeyToAccount(privateKey as Hex);
- localStorage.setItem(STORAGE_PREFIX + account.address, privateKey);
-
- return privateKey;
- };
-
- const removeSessionKey = async (publicKey: Address) => {
- await revokeAccess(publicKey);
- localStorage.removeItem(STORAGE_PREFIX + publicKey);
+ localStorage.setItem(HAPPY_STORAGE_PREFIX + playerAddress, "true");
+ } else return;
};
const hideHelp = () => {
@@ -73,75 +51,17 @@ export function Authorize() {
)}
- {sessionAddress ? (
+ {weAreHappySponsored ? (
-
AUTHORIZING
-
- {
- setShowDetails(false);
- revokeAccess(sessionAddress);
- removeSessionKey(sessionAddress);
- }}
- tooltip="stop authorizing"
- tooltipDirection="top"
- className="btn-sm btn-primary"
- >
-
-
- setShowDetails((prev) => !prev)}
- tooltipDirection="top"
- className="btn-sm btn-primary"
- >
- {showDetails ? : }
-
-
+
+ 🤠SESSION KEY REGISTERED ðŸ¤
+
- {showDetails && (
-
-
-
-
- Session Address:
- copyToClipboard(sessionAddress, "address")}
- tooltipDirection="top"
- >
-
-
- copyToClipboard(sessionAccount?.privateKey, "private key")}
- tooltipDirection="top"
- >
-
-
-
-
{sessionAddress}
-
-
-
- )}
) : (
- {
- const key = handleRandomPress();
- submitPrivateKey(key);
- }}
- >
- CLICK TO AUTHORIZE SESSION ACCOUNT
+
+ CLICK TO AUTHORIZE SESSION KEY
)}
diff --git a/packages/client/src/screens/Enter.tsx b/packages/client/src/screens/Enter.tsx
index 59db0889d..0ef3ed79b 100644
--- a/packages/client/src/screens/Enter.tsx
+++ b/packages/client/src/screens/Enter.tsx
@@ -1,32 +1,32 @@
+import { requestSessionKey } from "@happy.tech/core";
import { useEffect, useState } from "react";
import { FaExclamationTriangle, FaInfoCircle } from "react-icons/fa";
import { useLocation, useNavigate } from "react-router-dom";
import { toast } from "react-toastify";
-import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
-import { STORAGE_PREFIX } from "@primodiumxyz/core";
import { useAccountClient, useCore } from "@primodiumxyz/core/react";
import { defaultEntity } from "@primodiumxyz/reactive-tables";
import { Tooltip } from "@/components/core/Tooltip";
import { TransactionQueueMask } from "@/components/shared/TransactionQueueMask";
import { useContractCalls } from "@/hooks/useContractCalls";
-import { findEntriesWithPrefix } from "@/util/localStorage";
+import { HAPPY_STORAGE_PREFIX, isHappySessionKeyRegistered } from "@/util/localStorage";
import { Landing } from "./Landing";
export const Enter: React.FC = () => {
const { tables } = useCore();
const {
- playerAccount: { entity: playerEntity },
+ playerAccount: { address: playerAddress, worldContract, entity: playerEntity },
sessionAccount,
} = useAccountClient();
- const { grantAccessWithSignature, spawn } = useContractCalls();
+ const { spawn } = useContractCalls();
const navigate = useNavigate();
const location = useLocation();
const [showingToast, setShowingToast] = useState(false);
const [state, setState] = useState<"loading" | "delegate" | "play">("loading");
+
const confirmSkip = async () => {
toast.dismiss();
if (showingToast) await new Promise((resolve) => setTimeout(resolve, 500));
@@ -37,6 +37,9 @@ export const Enter: React.FC = () => {
Are you sure you want to skip? You will need to confirm every action with your external wallet.
+
+
+ You can still enable a session key within the game settings.
@@ -72,8 +75,9 @@ export const Enter: React.FC = () => {
},
);
};
+
useEffect(() => {
- if (!sessionAccount) {
+ if (!isHappySessionKeyRegistered(playerAddress)) {
setState("delegate");
} else {
setState("play");
@@ -93,13 +97,14 @@ export const Enter: React.FC = () => {
navigate("/game" + location.search);
};
- const handleDelegate = async () => {
- const storedKeys = findEntriesWithPrefix();
- const privateKey = storedKeys.length > 0 ? storedKeys[0].privateKey : generatePrivateKey();
- const account = privateKeyToAccount(privateKey);
- localStorage.setItem(STORAGE_PREFIX + account.address, privateKey);
+ const handleHappySessionKeyRegister = async () => {
+ if (!isHappySessionKeyRegistered(playerAddress)) {
+ // once this resolves, write a status into local storage that this has been done
+ await requestSessionKey(worldContract.address);
- await grantAccessWithSignature(privateKey, { id: defaultEntity });
+ localStorage.setItem(HAPPY_STORAGE_PREFIX + playerAddress, "true");
+ setState("play");
+ } else return;
};
return (
@@ -108,7 +113,7 @@ export const Enter: React.FC = () => {
{state === "delegate" && (
return true;
}
+ // this is fully for mud's delegate system - we may need none of this for happy session keys
const potentialAuthorizeds = query({ with: [tables.UserDelegationControl] }).reduce((prev, entity) => {
const key = decodeEntity(tables.UserDelegationControl.metadata.abiKeySchema, entity) as {
delegator: Address;
diff --git a/packages/client/src/util/localStorage.ts b/packages/client/src/util/localStorage.ts
index 7aaa5e576..361450fae 100644
--- a/packages/client/src/util/localStorage.ts
+++ b/packages/client/src/util/localStorage.ts
@@ -1,4 +1,4 @@
-import { Hex } from "viem";
+import { Address, Hex } from "viem";
import { STORAGE_PREFIX } from "@primodiumxyz/core";
@@ -35,3 +35,10 @@ export function getPrivateKey(publicKey: Hex): Hex | undefined {
if (!entry) return;
return entry as Hex;
}
+
+// [HAPPY_PRIM] storage helpers for session keys
+export const HAPPY_STORAGE_PREFIX = "[HAPPY_PRIM] sessionKeyRegistered:";
+
+export const isHappySessionKeyRegistered = (address: Address): boolean => {
+ return localStorage.getItem(HAPPY_STORAGE_PREFIX + address) === "true";
+};