diff --git a/packages/client/src/components/transfer/Authorize.tsx b/packages/client/src/components/transfer/Authorize.tsx index 1707b943d..5058ba8e8 100644 --- a/packages/client/src/components/transfer/Authorize.tsx +++ b/packages/client/src/components/transfer/Authorize.tsx @@ -1,7 +1,7 @@ +import { requestSessionKey } from "@happy.tech/core"; 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 { Address } from "viem"; import { STORAGE_PREFIX } from "@primodiumxyz/core"; import { useAccountClient } from "@primodiumxyz/core/react"; @@ -11,14 +11,21 @@ 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"; -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 { + playerAccount: { worldContract }, + sessionAccount, + } = useAccountClient(); + const { revokeAccess } = useContractCalls(); const [showDetails, setShowDetails] = useState(false); const [showHelp, setShowHelp] = useState(!localStorage.getItem("hideHelp")); @@ -29,26 +36,26 @@ export function Authorize() { // Function to handle private key validation and connection const sessionAddress = sessionAccount?.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); + // 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 }); - }; + // 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 _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); + // const account = privateKeyToAccount(privateKey as Hex); + // localStorage.setItem(STORAGE_PREFIX + account.address, privateKey); - return privateKey; - }; + // return privateKey; + // }; const removeSessionKey = async (publicKey: Address) => { await revokeAccess(publicKey); @@ -136,12 +143,13 @@ export function Authorize() { variant="primary" size="md" className="w-full" - onClick={() => { - const key = handleRandomPress(); - submitPrivateKey(key); + onClick={async () => { + // const key = handleRandomPress(); + // submitPrivateKey(key); + await requestSessionKey(worldContract.address); }} > - 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 0d1fb5ebb..827b0da87 100644 --- a/packages/client/src/screens/Enter.tsx +++ b/packages/client/src/screens/Enter.tsx @@ -1,27 +1,26 @@ +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 { Address } from "viem"; -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 } from "@/util/localStorage"; import { Landing } from "./Landing"; export const Enter: React.FC = () => { const { tables } = useCore(); const { - playerAccount: { entity: playerEntity }, - sessionAccount, + playerAccount: { address: playerAddress, worldContract, entity: playerEntity }, } = useAccountClient(); - const { grantAccessWithSignature, spawn } = useContractCalls(); + const { spawn } = useContractCalls(); const navigate = useNavigate(); const location = useLocation(); const [showingToast, setShowingToast] = useState(false); @@ -37,6 +36,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.
@@ -73,17 +75,17 @@ export const Enter: React.FC = () => { ); }; useEffect(() => { - if (!sessionAccount) { + if (!isSessionRegistered(playerAddress)) { setState("delegate"); } else { setState("play"); } - }, [sessionAccount]); + }, [playerAddress]); useEffect(() => { - if (!sessionAccount) return; - toast.success(`Session account detected! (${sessionAccount.address.slice(0, 7)})`); - }, [sessionAccount]); + if (!isSessionRegistered(playerAddress)) return; + toast.success(`Session account detected! (${playerAddress.slice(0, 7)})`); + }, [playerAddress]); const handlePlay = async () => { const hasSpawned = !!tables.Home.get(playerEntity)?.value; @@ -93,13 +95,17 @@ 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 isSessionRegistered = (address: Address): boolean => { + return localStorage.getItem(HAPPY_STORAGE_PREFIX + address) === "true"; + }; - await grantAccessWithSignature(privateKey, { id: defaultEntity }); + const handleRegisterHappySessionKey = async () => { + const isRegistered = isSessionRegistered(playerAddress); + if (!isRegistered) { + await requestSessionKey(worldContract.address); + localStorage.setItem(HAPPY_STORAGE_PREFIX + playerAddress, "true"); + setState("play"); + } else return; }; return ( @@ -108,7 +114,7 @@ export const Enter: React.FC = () => { {state === "delegate" && (
- Authorize Delegate + Register Session Key